From b6ef8b1803248227890ecefa3624bc9a4d97dced Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 26 Aug 2014 22:20:22 -0400 Subject: [PATCH 01/61] 1st pass at storing post attachments --- .../datasets/ReaderAttachmentTable.java | 101 ++++++++++++++++++ .../android/datasets/ReaderDatabase.java | 11 +- .../android/models/ReaderAttachment.java | 58 ++++++++++ .../android/models/ReaderAttachmentList.java | 27 +++++ 4 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java create mode 100644 WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java create mode 100644 WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java new file mode 100644 index 000000000000..745ad5ab07ea --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java @@ -0,0 +1,101 @@ +package org.wordpress.android.datasets; + +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; + +import org.wordpress.android.models.ReaderAttachment; +import org.wordpress.android.models.ReaderAttachmentList; +import org.wordpress.android.util.SqlUtils; + +/** + * stores attachments for reader posts + */ +public class ReaderAttachmentTable { + protected static void createTables(SQLiteDatabase db) { + db.execSQL("CREATE TABLE tbl_attachments (" + + " post_id INTEGER," + + " blog_id INTEGER," + + " attachment_id INTEGER," + + " url TEXT NOT NULL," + + " mime_type TEXT NOT NULL," + + " width INTEGER DEFAULT 0," + + " height INTEGER DEFAULT 0," + + " PRIMARY KEY (post_id, blog_id, attachment_id)" + + ")"); + } + + protected static void dropTables(SQLiteDatabase db) { + db.execSQL("DROP TABLE IF EXISTS tbl_attachments"); + } + + /* + * purge table of attachments to posts that no longer exist + */ + protected static int purge(SQLiteDatabase db) { + return db.delete("tbl_attachments", "post_id NOT IN (SELECT DISTINCT post_id FROM tbl_posts)", null); + } + + public static void setAttachmentsForPost(long blogId, long postId, ReaderAttachmentList attachments) { + SQLiteDatabase db = ReaderDatabase.getWritableDb(); + db.beginTransaction(); + SQLiteStatement stmt = db.compileStatement("INSERT INTO tbl_attachments (blog_id, post_id, attachment_id, url, mime_type, width, height) VALUES (?1,?2,?3,?4,?5,?6,?7)"); + try { + // first delete all attachments for this post + String[] args = {Long.toString(blogId), Long.toString(postId)}; + db.delete("tbl_attachments", "blog_id=? AND post_id=?", args); + + // now insert the passed ones + if (attachments != null) { + stmt.bindLong(1, blogId); + stmt.bindLong(2, postId); + for (ReaderAttachment attach: attachments) { + stmt.bindLong (3, attach.attachmentId); + stmt.bindString(4, attach.getUrl()); + stmt.bindString(5, attach.getMimeType()); + stmt.bindLong(6, attach.width); + stmt.bindLong (7, attach.height); + stmt.execute(); + } + } + + db.setTransactionSuccessful(); + + } finally { + db.endTransaction(); + SqlUtils.closeStatement(stmt); + } + } + + public static ReaderAttachmentList getAttachmentsForPost(long blogId, long postId) { + String[] args = {Long.toString(blogId), Long.toString(postId)}; + Cursor c = ReaderDatabase.getReadableDb().rawQuery("SELECT * FROM tbl_attachments WHERE blog_id=? AND post_id=?", args); + try { + ReaderAttachmentList attachments = new ReaderAttachmentList(); + if (c.moveToFirst()) { + do { + attachments.add(getAttachmentFromCursor(c)); + } while (c.moveToNext()); + } + return attachments; + } finally { + SqlUtils.closeCursor(c); + } + } + + private static ReaderAttachment getAttachmentFromCursor(Cursor c) { + ReaderAttachment attach = new ReaderAttachment(); + + attach.blogId = c.getLong(c.getColumnIndex("blog_id")); + attach.postId = c.getLong(c.getColumnIndex("post_id")); + attach.attachmentId = c.getLong(c.getColumnIndex("attachment_id")); + + attach.setUrl(c.getString(c.getColumnIndex("url"))); + attach.setMimeType(c.getString(c.getColumnIndex("mime_type"))); + + attach.height = c.getInt(c.getColumnIndex("height")); + attach.width = c.getInt(c.getColumnIndex("width")); + + return attach; + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java index abe69084ec24..3a3d495110eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java @@ -19,7 +19,7 @@ */ public class ReaderDatabase extends SQLiteOpenHelper { protected static final String DB_NAME = "wpreader.db"; - private static final int DB_VERSION = 83; + private static final int DB_VERSION = 84; /* * version history @@ -40,6 +40,7 @@ public class ReaderDatabase extends SQLiteOpenHelper { * 81 - added image_url to tbl_blog_info * 82 - added idx_posts_timestamp to tbl_posts * 83 - removed tag_list from tbl_posts + * 84 - added tbl_attachments */ /* @@ -115,6 +116,7 @@ private void createAllTables(SQLiteDatabase db) { ReaderUserTable.createTables(db); ReaderThumbnailTable.createTables(db); ReaderBlogTable.createTables(db); + ReaderAttachmentTable.createTables(db); } private void dropAllTables(SQLiteDatabase db) { @@ -125,6 +127,7 @@ private void dropAllTables(SQLiteDatabase db) { ReaderUserTable.dropTables(db); ReaderThumbnailTable.dropTables(db); ReaderBlogTable.dropTables(db); + ReaderAttachmentTable.dropTables(db); } /* @@ -177,6 +180,12 @@ private static void purge() { if (numTagsPurged > 0) { AppLog.i(T.READER, String.format("%d tags purged", numTagsPurged)); } + + // purge unattached post attachments + int numAttachPurged = ReaderAttachmentTable.purge(db); + if (numAttachPurged > 0) { + AppLog.i(T.READER, String.format("%d attachments purged", numAttachPurged)); + } } db.setTransactionSuccessful(); } finally { diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java new file mode 100644 index 000000000000..6cbf22b802fe --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java @@ -0,0 +1,58 @@ +package org.wordpress.android.models; + +import org.json.JSONObject; +import org.wordpress.android.util.JSONUtil; +import org.wordpress.android.util.StringUtils; + +public class ReaderAttachment { + public long postId; + public long blogId; + public long attachmentId; + + private String url; + private String mimeType; + + public int width; + public int height; + + /* + 2211": { + "ID": 2211, + "URL": "https://mroselamb.files.wordpress.com/2014/08/img_5939.jpg", + "guid": "http://mroselamb.files.wordpress.com/2014/08/img_5939.jpg", + "mime_type": "image/jpeg", + "width": 2448, + "height": 2448 + }, + */ + public static ReaderAttachment fromJson(long blogId, long postId, JSONObject json) { + ReaderAttachment attach = new ReaderAttachment(); + if (json == null) { + return attach; + } + + attach.blogId = blogId; + attach.postId = postId; + + attach.attachmentId = json.optLong("ID"); + attach.mimeType = JSONUtil.getString(json, "mime_type"); + attach.url = JSONUtil.getString(json, "URL"); + attach.width = json.optInt("width"); + attach.height = json.optInt("height"); + + return attach; + } + + public String getUrl() { + return StringUtils.notNullStr(url); + } + public void setUrl(String url) { + this.url = StringUtils.notNullStr(url); + } + + public String getMimeType() { + return StringUtils.notNullStr(mimeType); + } + public void setMimeType(String mimeType) { + this.mimeType = StringUtils.notNullStr(mimeType); + }} diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java new file mode 100644 index 000000000000..c539ec708642 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java @@ -0,0 +1,27 @@ +package org.wordpress.android.models; + +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Iterator; + +public class ReaderAttachmentList extends ArrayList { + + public static ReaderAttachmentList fromJson(long blogId, long postId, JSONObject json) { + ReaderAttachmentList attachments = new ReaderAttachmentList(); + if (json == null) { + return attachments; + } + + Iterator it = json.keys(); + if (!it.hasNext()) { + return attachments; + } + + while (it.hasNext()) { + JSONObject jsonAttach = json.optJSONObject(it.next()); + attachments.add(ReaderAttachment.fromJson(blogId, postId, jsonAttach)); + } + + return attachments; + }} From df0a3253bc5b8827dfbf6201a47633061a55e795 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 26 Aug 2014 22:32:46 -0400 Subject: [PATCH 02/61] 2nd pass at storing post attachments --- .../datasets/ReaderAttachmentTable.java | 32 +++++++++---------- .../wordpress/android/models/ReaderPost.java | 20 ++++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java index 745ad5ab07ea..b5ed7f2a22a8 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java @@ -36,6 +36,22 @@ protected static int purge(SQLiteDatabase db) { return db.delete("tbl_attachments", "post_id NOT IN (SELECT DISTINCT post_id FROM tbl_posts)", null); } + public static ReaderAttachmentList getAttachmentsForPost(long blogId, long postId) { + String[] args = {Long.toString(blogId), Long.toString(postId)}; + Cursor c = ReaderDatabase.getReadableDb().rawQuery("SELECT * FROM tbl_attachments WHERE blog_id=? AND post_id=?", args); + try { + ReaderAttachmentList attachments = new ReaderAttachmentList(); + if (c.moveToFirst()) { + do { + attachments.add(getAttachmentFromCursor(c)); + } while (c.moveToNext()); + } + return attachments; + } finally { + SqlUtils.closeCursor(c); + } + } + public static void setAttachmentsForPost(long blogId, long postId, ReaderAttachmentList attachments) { SQLiteDatabase db = ReaderDatabase.getWritableDb(); db.beginTransaction(); @@ -67,22 +83,6 @@ public static void setAttachmentsForPost(long blogId, long postId, ReaderAttachm } } - public static ReaderAttachmentList getAttachmentsForPost(long blogId, long postId) { - String[] args = {Long.toString(blogId), Long.toString(postId)}; - Cursor c = ReaderDatabase.getReadableDb().rawQuery("SELECT * FROM tbl_attachments WHERE blog_id=? AND post_id=?", args); - try { - ReaderAttachmentList attachments = new ReaderAttachmentList(); - if (c.moveToFirst()) { - do { - attachments.add(getAttachmentFromCursor(c)); - } while (c.moveToNext()); - } - return attachments; - } finally { - SqlUtils.closeCursor(c); - } - } - private static ReaderAttachment getAttachmentFromCursor(Cursor c) { ReaderAttachment attach = new ReaderAttachment(); diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java index 0290b69484ce..0756cb4b7499 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java @@ -52,6 +52,8 @@ public class ReaderPost { public boolean isLikesEnabled; public boolean isSharingEnabled; // currently unused + private ReaderAttachmentList attachments; + public static ReaderPost fromJson(JSONObject json) { if (json == null) { throw new IllegalArgumentException("null json post"); @@ -155,6 +157,9 @@ public static ReaderPost fromJson(JSONObject json) { // parse the tags section assignTagsFromJson(post, json.optJSONObject("tags")); + // parse the attachments + assignAttachmentsFromJson(post, json.optJSONObject("attachments")); + // the single-post sites/$site/posts/$post endpoint returns all site metadata // under meta/data/site (assuming ?meta=site was added to the request) JSONObject jsonSite = JSONUtil.getJSONChild(json, "meta/data/site"); @@ -168,6 +173,10 @@ public static ReaderPost fromJson(JSONObject json) { return post; } + private static void assignAttachmentsFromJson(ReaderPost post, JSONObject jsonAttachments) { + post.setAttachments(ReaderAttachmentList.fromJson(post.blogId, post.postId, jsonAttachments)); + } + /* * assigns author-related info to the passed post from the passed JSON "author" object */ @@ -420,6 +429,17 @@ public boolean isWP() { return !isExternal; } + public ReaderAttachmentList getAttachments() { + return attachments; + } + public void setAttachments(ReaderAttachmentList attachments) { + if (attachments != null) { + attachments = (ReaderAttachmentList) attachments.clone(); + } else { + attachments = new ReaderAttachmentList(); + } + } + /**** * the following are transient variables - not stored in the db or returned in the json - whose * sole purpose is to cache commonly-used values for the post that speeds up using them inside From 8d595f88eb9bb22b2e197548233ac98341f4a0ac Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 26 Aug 2014 22:55:09 -0400 Subject: [PATCH 03/61] 3rd pass at storing post attachments --- .../wordpress/android/datasets/ReaderPostTable.java | 9 +++++++++ .../org/wordpress/android/models/ReaderPost.java | 12 ++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java index 6bc66eafdee9..fcc3f70131d0 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java @@ -427,6 +427,13 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { } } + // save attachments for these posts + for (ReaderPost post: posts) { + if (post.hasAttachments()) { + ReaderAttachmentTable.setAttachmentsForPost(post.blogId, post.postId, post.getAttachments()); + } + } + db.setTransactionSuccessful(); } finally { @@ -652,6 +659,8 @@ private static ReaderPost getPostFromCursor(Cursor c, PostColumnIndexes cols) { post.isLikesEnabled = SqlUtils.sqlToBool(c.getInt(cols.idx_is_likes_enabled)); post.isSharingEnabled = SqlUtils.sqlToBool(c.getInt(cols.idx_is_sharing_enabled)); + post.setAttachments(ReaderAttachmentTable.getAttachmentsForPost(post.blogId, post.postId)); + return post; } } diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java index 0756cb4b7499..df1bf77ad477 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java @@ -352,8 +352,6 @@ public void setPublished(String published) { this.published = StringUtils.notNullStr(published); } - // -------------------------------------------------------------------------------------------- - public String getPrimaryTag() { return StringUtils.notNullStr(primaryTag); } @@ -377,8 +375,6 @@ public void setSecondaryTag(String tagName) { } } - // -------------------------------------------------------------------------------------------- - public boolean hasText() { return !TextUtils.isEmpty(text); } @@ -429,17 +425,21 @@ public boolean isWP() { return !isExternal; } + public boolean hasAttachments() { + return (attachments != null && attachments.size() > 0); + } public ReaderAttachmentList getAttachments() { return attachments; } public void setAttachments(ReaderAttachmentList attachments) { if (attachments != null) { - attachments = (ReaderAttachmentList) attachments.clone(); + this.attachments = (ReaderAttachmentList) attachments.clone(); } else { - attachments = new ReaderAttachmentList(); + this.attachments = new ReaderAttachmentList(); } } + /**** * the following are transient variables - not stored in the db or returned in the json - whose * sole purpose is to cache commonly-used values for the post that speeds up using them inside From 48cf191f87600f66768dc51a1580316f2b3f936b Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 26 Aug 2014 23:24:02 -0400 Subject: [PATCH 04/61] 4th pass at storing post attachments --- .../datasets/ReaderAttachmentTable.java | 46 +++++++++++-------- .../android/datasets/ReaderPostTable.java | 8 +--- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java index b5ed7f2a22a8..f4d9c718b644 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java @@ -6,6 +6,8 @@ import org.wordpress.android.models.ReaderAttachment; import org.wordpress.android.models.ReaderAttachmentList; +import org.wordpress.android.models.ReaderPost; +import org.wordpress.android.models.ReaderPostList; import org.wordpress.android.util.SqlUtils; /** @@ -52,31 +54,37 @@ public static ReaderAttachmentList getAttachmentsForPost(long blogId, long postI } } - public static void setAttachmentsForPost(long blogId, long postId, ReaderAttachmentList attachments) { + public static void saveAttachmentsForPosts(ReaderPostList posts) { + if (posts == null || posts.size() == 0) { + return; + } + SQLiteDatabase db = ReaderDatabase.getWritableDb(); db.beginTransaction(); - SQLiteStatement stmt = db.compileStatement("INSERT INTO tbl_attachments (blog_id, post_id, attachment_id, url, mime_type, width, height) VALUES (?1,?2,?3,?4,?5,?6,?7)"); + SQLiteStatement stmt = db.compileStatement( + "INSERT INTO tbl_attachments" + + " (blog_id, post_id, attachment_id, url, mime_type, width, height)" + + " VALUES (?1,?2,?3,?4,?5,?6,?7)"); try { - // first delete all attachments for this post - String[] args = {Long.toString(blogId), Long.toString(postId)}; - db.delete("tbl_attachments", "blog_id=? AND post_id=?", args); + for (ReaderPost post : posts) { + if (post.hasAttachments()) { + // first delete all attachments for this post + String[] args = {Long.toString(post.blogId), Long.toString(post.postId)}; + db.delete("tbl_attachments", "blog_id=? AND post_id=?", args); - // now insert the passed ones - if (attachments != null) { - stmt.bindLong(1, blogId); - stmt.bindLong(2, postId); - for (ReaderAttachment attach: attachments) { - stmt.bindLong (3, attach.attachmentId); - stmt.bindString(4, attach.getUrl()); - stmt.bindString(5, attach.getMimeType()); - stmt.bindLong(6, attach.width); - stmt.bindLong (7, attach.height); - stmt.execute(); + // now insert the passed ones + stmt.bindLong(1, post.blogId); + stmt.bindLong(2, post.postId); + for (ReaderAttachment attach : post.getAttachments()) { + stmt.bindLong (3, attach.attachmentId); + stmt.bindString(4, attach.getUrl()); + stmt.bindString(5, attach.getMimeType()); + stmt.bindLong (6, attach.width); + stmt.bindLong (7, attach.height); + stmt.execute(); + } } } - - db.setTransactionSuccessful(); - } finally { db.endTransaction(); SqlUtils.closeStatement(stmt); diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java index fcc3f70131d0..fb0369182b2b 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java @@ -427,12 +427,8 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { } } - // save attachments for these posts - for (ReaderPost post: posts) { - if (post.hasAttachments()) { - ReaderAttachmentTable.setAttachmentsForPost(post.blogId, post.postId, post.getAttachments()); - } - } + // save attachments for posts that have any + ReaderAttachmentTable.saveAttachmentsForPosts(posts); db.setTransactionSuccessful(); From 4e9a4cca6598664bcb3f347af125a11a0d8b5354 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 27 Aug 2014 08:05:34 -0400 Subject: [PATCH 05/61] Fixed db transaction bug saving attachments --- .../org/wordpress/android/datasets/ReaderAttachmentTable.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java index f4d9c718b644..574ba72cb5c6 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java @@ -60,7 +60,6 @@ public static void saveAttachmentsForPosts(ReaderPostList posts) { } SQLiteDatabase db = ReaderDatabase.getWritableDb(); - db.beginTransaction(); SQLiteStatement stmt = db.compileStatement( "INSERT INTO tbl_attachments" + " (blog_id, post_id, attachment_id, url, mime_type, width, height)" @@ -86,7 +85,6 @@ public static void saveAttachmentsForPosts(ReaderPostList posts) { } } } finally { - db.endTransaction(); SqlUtils.closeStatement(stmt); } } From f5c0d65b8a0ad3a99d63953fc6183ca73c6db0cb Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 05:53:55 -0400 Subject: [PATCH 06/61] Added a few utility functions --- .../android/models/ReaderAttachment.java | 42 ++++++++++++------- .../android/models/ReaderAttachmentList.java | 3 +- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java index 6cbf22b802fe..b2e4b40aa3d1 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java @@ -3,6 +3,7 @@ import org.json.JSONObject; import org.wordpress.android.util.JSONUtil; import org.wordpress.android.util.StringUtils; +import org.wordpress.android.util.UrlUtils; public class ReaderAttachment { public long postId; @@ -15,16 +16,6 @@ public class ReaderAttachment { public int width; public int height; - /* - 2211": { - "ID": 2211, - "URL": "https://mroselamb.files.wordpress.com/2014/08/img_5939.jpg", - "guid": "http://mroselamb.files.wordpress.com/2014/08/img_5939.jpg", - "mime_type": "image/jpeg", - "width": 2448, - "height": 2448 - }, - */ public static ReaderAttachment fromJson(long blogId, long postId, JSONObject json) { ReaderAttachment attach = new ReaderAttachment(); if (json == null) { @@ -33,10 +24,11 @@ public static ReaderAttachment fromJson(long blogId, long postId, JSONObject jso attach.blogId = blogId; attach.postId = postId; - attach.attachmentId = json.optLong("ID"); - attach.mimeType = JSONUtil.getString(json, "mime_type"); - attach.url = JSONUtil.getString(json, "URL"); + + attach.setMimeType(JSONUtil.getString(json, "mime_type")); + attach.setUrl(JSONUtil.getString(json, "URL")); + attach.width = json.optInt("width"); attach.height = json.optInt("height"); @@ -48,6 +40,15 @@ public String getUrl() { } public void setUrl(String url) { this.url = StringUtils.notNullStr(url); + normUrl = null; + } + + private transient String normUrl; + public String getNormUrl() { + if (normUrl == null) { + normUrl = UrlUtils.normalizeUrl(url); + } + return normUrl; } public String getMimeType() { @@ -55,4 +56,17 @@ public String getMimeType() { } public void setMimeType(String mimeType) { this.mimeType = StringUtils.notNullStr(mimeType); - }} + } + + public float getHWRatio() { + if (width == 0 || height == 0) { + return 0; + } else { + return ((float) height / (float) width); + } + } + + public boolean isImage() { + return (mimeType != null && mimeType.startsWith("image")); + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java index c539ec708642..67f192a32b3b 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java @@ -24,4 +24,5 @@ public static ReaderAttachmentList fromJson(long blogId, long postId, JSONObject } return attachments; - }} + } +} From 611953cf13c8e36a48be97ba2837d244b929480a Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 08:19:45 -0400 Subject: [PATCH 07/61] Moved ReaderResourceVars to its own class file --- .../android/models/ReaderAttachmentList.java | 16 +++++ .../ui/reader/ReaderPostDetailFragment.java | 61 +----------------- .../android/ui/reader/ReaderPostRenderer.java | 13 ++++ .../android/ui/reader/ReaderResourceVars.java | 63 +++++++++++++++++++ 4 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java index 67f192a32b3b..cc114257573e 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java @@ -1,6 +1,7 @@ package org.wordpress.android.models; import org.json.JSONObject; +import org.wordpress.android.util.UrlUtils; import java.util.ArrayList; import java.util.Iterator; @@ -25,4 +26,19 @@ public static ReaderAttachmentList fromJson(long blogId, long postId, JSONObject return attachments; } + + public ReaderAttachment get(final String imageUrl) { + if (imageUrl == null) { + return null; + } + + String normUrl = UrlUtils.normalizeUrl(imageUrl); + for (ReaderAttachment attachment: this) { + if (normUrl.equals(attachment.getNormUrl())) { + return attachment; + } + } + + return null; + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 28ff8bc6935e..abd7fe173e87 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -5,7 +5,6 @@ import android.app.Fragment; import android.content.Context; import android.content.Intent; -import android.content.res.Resources; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; @@ -36,7 +35,6 @@ import org.wordpress.android.datasets.ReaderPostTable; import org.wordpress.android.models.ReaderComment; import org.wordpress.android.models.ReaderPost; -import org.wordpress.android.ui.WPActionBarActivity; import org.wordpress.android.ui.reader.ReaderActivityLauncher.OpenUrlType; import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType; import org.wordpress.android.ui.reader.ReaderWebView.ReaderCustomViewListener; @@ -55,7 +53,6 @@ import org.wordpress.android.util.DateTimeUtils; import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.EditTextUtils; -import org.wordpress.android.util.HtmlUtils; import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.StringUtils; import org.wordpress.android.util.ToastUtils; @@ -102,7 +99,7 @@ public class ReaderPostDetailFragment extends Fragment private int mPrevScrollState = SCROLL_STATE_IDLE; private Parcelable mListState; - private ResourceVars mResourceVars; + private ReaderResourceVars mResourceVars; private ReaderUtils.FullScreenListener mFullScreenListener; @@ -130,60 +127,6 @@ public static ReaderPostDetailFragment newInstance(long blogId, return fragment; } - /* - * class which holds all resource-based variables used by this fragment - */ - private static class ResourceVars { - final int displayWidth; - final int actionBarHeight; - final int likeAvatarSize; - final int videoOverlaySize; - - final int marginLarge; - final int marginSmall; - final int marginExtraSmall; - final int listMarginWidth; - final int fullSizeImageWidth; - - final int colorGreyExtraLight; - final int mediumAnimTime; - - final String linkColorStr; - final String greyLightStr; - final String greyExtraLightStr; - - private ResourceVars(Context context) { - Resources resources = context.getResources(); - - displayWidth = DisplayUtils.getDisplayPixelWidth(context); - actionBarHeight = DisplayUtils.getActionBarHeight(context); - likeAvatarSize = resources.getDimensionPixelSize(R.dimen.avatar_sz_small); - videoOverlaySize = resources.getDimensionPixelSize(R.dimen.reader_video_overlay_size); - - marginLarge = resources.getDimensionPixelSize(R.dimen.margin_large); - marginSmall = resources.getDimensionPixelSize(R.dimen.margin_small); - marginExtraSmall = resources.getDimensionPixelSize(R.dimen.margin_extra_small); - listMarginWidth = 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); - greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light); - greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light); - - int imageWidth = displayWidth - (listMarginWidth * 2); - boolean hasStaticMenuDrawer = - (context instanceof WPActionBarActivity) - && (((WPActionBarActivity) context).isStaticMenuDrawer()); - if (hasStaticMenuDrawer) { - int drawerWidth = resources.getDimensionPixelOffset(R.dimen.menu_drawer_width); - imageWidth -= drawerWidth; - } - fullSizeImageWidth = imageWidth; - } - } - /* * adapter containing comments for this post */ @@ -286,7 +229,7 @@ public void setArguments(Bundle args) { public void onAttach(Activity activity) { super.onAttach(activity); - mResourceVars = new ResourceVars(activity); + mResourceVars = new ReaderResourceVars(activity); if (activity instanceof ReaderUtils.FullScreenListener) { mFullScreenListener = (ReaderUtils.FullScreenListener) activity; 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..3590b8201211 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -0,0 +1,13 @@ +package org.wordpress.android.ui.reader; + +import android.content.Context; + +/** + * Created by nbradbury on 8/28/14. + */ +public class ReaderPostRenderer { + + ReaderPostRenderer(Context context) { + + } +} 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..6162ad27ea20 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -0,0 +1,63 @@ +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 by this fragment + */ +class ReaderResourceVars { + final int displayWidth; + final int actionBarHeight; + final int likeAvatarSize; + final int videoOverlaySize; + + final int marginLarge; + final int marginSmall; + final int marginExtraSmall; + final int listMarginWidth; + final int fullSizeImageWidth; + + final int colorGreyExtraLight; + final int mediumAnimTime; + + final String linkColorStr; + final String greyLightStr; + final String greyExtraLightStr; + + ReaderResourceVars(Context context) { + Resources resources = context.getResources(); + + displayWidth = DisplayUtils.getDisplayPixelWidth(context); + actionBarHeight = DisplayUtils.getActionBarHeight(context); + likeAvatarSize = resources.getDimensionPixelSize(R.dimen.avatar_sz_small); + videoOverlaySize = resources.getDimensionPixelSize(R.dimen.reader_video_overlay_size); + + marginLarge = resources.getDimensionPixelSize(R.dimen.margin_large); + marginSmall = resources.getDimensionPixelSize(R.dimen.margin_small); + marginExtraSmall = resources.getDimensionPixelSize(R.dimen.margin_extra_small); + listMarginWidth = 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); + greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light); + greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light); + + int imageWidth = displayWidth - (listMarginWidth * 2); + boolean hasStaticMenuDrawer = + (context instanceof WPActionBarActivity) + && (((WPActionBarActivity) context).isStaticMenuDrawer()); + if (hasStaticMenuDrawer) { + int drawerWidth = resources.getDimensionPixelOffset(R.dimen.menu_drawer_width); + imageWidth -= drawerWidth; + } + fullSizeImageWidth = imageWidth; + } +} From fbe24df3f5f3c01ee33f7f63b3c2a329f017f37b Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 08:28:42 -0400 Subject: [PATCH 08/61] Moved formatting code over to ReaderPostRenderer --- .../ui/reader/ReaderPostDetailFragment.java | 180 +----------------- .../android/ui/reader/ReaderPostRenderer.java | 177 ++++++++++++++++- 2 files changed, 184 insertions(+), 173 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index abd7fe173e87..93f70e487775 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -3,9 +3,7 @@ import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; -import android.content.Context; import android.content.Intent; -import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; @@ -51,10 +49,7 @@ import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.DateTimeUtils; -import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.EditTextUtils; -import org.wordpress.android.util.PhotonUtils; -import org.wordpress.android.util.StringUtils; import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.UrlUtils; import org.wordpress.android.widgets.WPListView; @@ -74,6 +69,7 @@ public class ReaderPostDetailFragment extends Fragment private long mPostId; private long mBlogId; private ReaderPost mPost; + private ReaderPostRenderer mRenderer; private ReaderPostListType mPostListType; @@ -948,33 +944,7 @@ private void refreshFollowed() { ReaderUtils.showFollowStatus(txtFollow, isFollowed); } - /* - * creates formatted div for passed video with passed (optional) thumbnail - */ - private static final String OVERLAY_IMG = "file:///android_asset/ic_reader_video_overlay.png"; - - private String makeVideoDiv(String videoUrl, String thumbnailUrl) { - if (TextUtils.isEmpty(videoUrl)) { - return ""; - } - - // sometimes we get src values like "//player.vimeo.com/video/70534716" - prefix these with http: - if (videoUrl.startsWith("//")) { - videoUrl = "http:" + videoUrl; - } - - int overlaySz = mResourceVars.videoOverlaySize / 2; - if (TextUtils.isEmpty(thumbnailUrl)) { - return String.format("
", videoUrl, overlaySz, overlaySz, OVERLAY_IMG); - } else { - return "
" - + String.format("", videoUrl, thumbnailUrl) - + String.format("", videoUrl, OVERLAY_IMG, overlaySz, overlaySz) - + "
"; - } - } - - 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; } @@ -985,12 +955,13 @@ private boolean showPhotoViewer(String imageUrl, View source, int startX, int st } boolean isPrivatePost = (mPost != null && mPost.isPrivate); + String postContent = (mRenderer != null ? mRenderer.getPostContent() : null); ReaderActivityLauncher.showReaderPhotoViewer( getActivity(), imageUrl, - getPostContent(), - source, + postContent, + sourceView, isPrivatePost, startX, startY); @@ -998,134 +969,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 */ @@ -1159,13 +1002,6 @@ 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"); @@ -1216,6 +1052,8 @@ protected Boolean doInBackground(Void... params) { return false; } + mRenderer = new ReaderPostRenderer(container.getContext(), mPost); + txtTitle = (TextView) container.findViewById(R.id.text_title); txtBlogName = (TextView) container.findViewById(R.id.text_blog_name); txtFollow = (TextView) container.findViewById(R.id.text_follow); @@ -1230,7 +1068,7 @@ protected Boolean doInBackground(Void... params) { layoutDetailHeader = (ViewGroup) container.findViewById(R.id.layout_detail_header); - postHtml = getPostContentForWebView(container.getContext()); + postHtml = mRenderer.getPostContentForWebView(container.getContext()); return true; } @@ -1254,7 +1092,7 @@ protected void onPostExecute(Boolean result) { } // enable JavaScript in the webView if it's safe to do so - mReaderWebView.getSettings().setJavaScriptEnabled(canEnableJavaScript()); + mReaderWebView.getSettings().setJavaScriptEnabled(ReaderPostRenderer.canEnableJavaScript(mPost)); // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail // https://code.google.com/p/android/issues/detail?id=4401 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 index 3590b8201211..02b3bb8bb7e2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -1,13 +1,186 @@ package org.wordpress.android.ui.reader; import android.content.Context; +import android.net.Uri; +import android.text.TextUtils; + +import org.wordpress.android.models.ReaderPost; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.DisplayUtils; +import org.wordpress.android.util.PhotonUtils; +import org.wordpress.android.util.StringUtils; /** - * Created by nbradbury on 8/28/14. + * generates the HTML for displaying post detail content */ public class ReaderPostRenderer { - ReaderPostRenderer(Context context) { + private final ReaderResourceVars mResourceVars; + private final ReaderPost mPost; + + ReaderPostRenderer(Context context, ReaderPost post) { + mResourceVars = new ReaderResourceVars(context); + mPost = post; + } + + /* + * returns the basic content of the post tweaked for use here + */ + 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(AppLog.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 + */ + 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(); + } + + /* + * creates formatted div for passed video with passed (optional) thumbnail + */ + private static final String OVERLAY_IMG = "file:///android_asset/ic_reader_video_overlay.png"; + + private String makeVideoDiv(String videoUrl, String thumbnailUrl) { + if (TextUtils.isEmpty(videoUrl)) { + return ""; + } + + // sometimes we get src values like "//player.vimeo.com/video/70534716" - prefix these with http: + if (videoUrl.startsWith("//")) { + videoUrl = "http:" + videoUrl; + } + + int overlaySz = mResourceVars.videoOverlaySize / 2; + if (TextUtils.isEmpty(thumbnailUrl)) { + return String.format("
", videoUrl, overlaySz, overlaySz, OVERLAY_IMG); + } else { + return "
" + + String.format("", videoUrl, thumbnailUrl) + + String.format("", videoUrl, OVERLAY_IMG, overlaySz, overlaySz) + + "
"; + } + } + /* + * javascript should only be enabled for wp blogs (not external feeds) + */ + static boolean canEnableJavaScript(ReaderPost post) { + return (post != null && post.isWP()); } } From 478069dc9a7d83512060bed9220563a0d157c6b4 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 09:44:59 -0400 Subject: [PATCH 09/61] Basic mechanism in place for rendering post content after image scan --- .../android/models/ReaderAttachment.java | 14 +-- .../android/models/ReaderAttachmentList.java | 4 +- .../ui/reader/ReaderPostDetailFragment.java | 13 +-- .../android/ui/reader/ReaderPostRenderer.java | 93 +++++++++++++++---- .../android/ui/reader/ReaderResourceVars.java | 6 ++ .../ui/reader/utils/ReaderImageScanner.java | 27 ++++++ 6 files changed, 117 insertions(+), 40 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java index b2e4b40aa3d1..1f364254b615 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java @@ -39,16 +39,12 @@ public String getUrl() { return StringUtils.notNullStr(url); } public void setUrl(String url) { - this.url = StringUtils.notNullStr(url); - normUrl = null; - } - - private transient String normUrl; - public String getNormUrl() { - if (normUrl == null) { - normUrl = UrlUtils.normalizeUrl(url); + // always store normalized URLs without a query string + if (url != null) { + this.url = UrlUtils.normalizeUrl(UrlUtils.removeQuery(url)); + } else { + this.url = ""; } - return normUrl; } public String getMimeType() { diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java index cc114257573e..73a98fc89c51 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java @@ -32,9 +32,9 @@ public ReaderAttachment get(final String imageUrl) { return null; } - String normUrl = UrlUtils.normalizeUrl(imageUrl); + String normUrl = UrlUtils.normalizeUrl(UrlUtils.removeQuery(imageUrl)); for (ReaderAttachment attachment: this) { - if (normUrl.equals(attachment.getNormUrl())) { + if (normUrl.equals(attachment.getUrl())) { return attachment; } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 93f70e487775..ed1e0b53d799 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1028,8 +1028,6 @@ private class ShowPostTask extends AsyncTask { WPNetworkImageView imgAvatar; ViewGroup layoutDetailHeader; - String postHtml; - @Override protected void onPreExecute() { mIsPostTaskRunning = true; @@ -1052,8 +1050,6 @@ protected Boolean doInBackground(Void... params) { return false; } - mRenderer = new ReaderPostRenderer(container.getContext(), mPost); - txtTitle = (TextView) container.findViewById(R.id.text_title); txtBlogName = (TextView) container.findViewById(R.id.text_blog_name); txtFollow = (TextView) container.findViewById(R.id.text_follow); @@ -1068,8 +1064,6 @@ protected Boolean doInBackground(Void... params) { layoutDetailHeader = (ViewGroup) container.findViewById(R.id.layout_detail_header); - postHtml = mRenderer.getPostContentForWebView(container.getContext()); - return true; } @@ -1094,9 +1088,9 @@ protected void onPostExecute(Boolean result) { // enable JavaScript in the webView if it's safe to do so mReaderWebView.getSettings().setJavaScriptEnabled(ReaderPostRenderer.canEnableJavaScript(mPost)); - // 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)); @@ -1212,7 +1206,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/ReaderPostRenderer.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java index 02b3bb8bb7e2..8180ed2d974e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -1,15 +1,18 @@ package org.wordpress.android.ui.reader; -import android.content.Context; import android.net.Uri; import android.text.TextUtils; +import org.wordpress.android.models.ReaderAttachment; +import org.wordpress.android.models.ReaderAttachmentList; import org.wordpress.android.models.ReaderPost; +import org.wordpress.android.ui.reader.utils.ReaderImageScanner; import org.wordpress.android.util.AppLog; -import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.StringUtils; +import java.lang.ref.WeakReference; + /** * generates the HTML for displaying post detail content */ @@ -17,19 +20,80 @@ public class ReaderPostRenderer { private final ReaderResourceVars mResourceVars; private final ReaderPost mPost; + private final WeakReference mWeakWebView; + + private String mRenderContent; + + ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { + if (post == null) { + throw new IllegalArgumentException("ReaderPostRenderer requires a post"); + } + if (webView == null) { + throw new IllegalArgumentException("ReaderPostRenderer requires a webView"); + } - ReaderPostRenderer(Context context, ReaderPost post) { - mResourceVars = new ReaderResourceVars(context); mPost = post; + mWeakWebView = new WeakReference(webView); + mResourceVars = new ReaderResourceVars(webView.getContext()); + } + + void beginRender() { + // start with the basic content + mRenderContent = getPostContent(); + + // if there aren't any attachments, we're done + if (!mPost.hasAttachments()) { + endRender(); + return; + } + + // start image scanner to find images, match them with attachments to get h/w ratio, then + // replace h/w attributes with correct ones for display + final ReaderAttachmentList attachments = mPost.getAttachments(); + ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { + @Override + public void onImageFound(String imageTag, String imageUrl, int start, int end) { + AppLog.d(AppLog.T.READER, "reader renderer > found " + imageUrl); + ReaderAttachment attach = attachments.get(imageUrl); + if (attach != null) { + AppLog.d(AppLog.T.READER, "reader renderer > matched attachment " + imageUrl); + setImageSize(imageTag, imageUrl, attach); + } + } + @Override + public void onScanCompleted() { + AppLog.d(AppLog.T.READER, "reader renderer > image scan completed"); + endRender(); + }; + }; + ReaderImageScanner scanner = new ReaderImageScanner(mRenderContent, mPost.isPrivate); + scanner.beginScan(imageListener); + } + + void endRender() { + ReaderWebView webView = mWeakWebView.get(); + if (webView == null) { + AppLog.w(AppLog.T.READER, "reader renderer > null webView"); + return; + } + + AppLog.d(AppLog.T.READER, "reader renderer > rendering content"); + + // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail + // https://code.google.com/p/android/issues/detail?id=4401 + String htmlContent = getPostContentForWebView(mRenderContent); + webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); + } + + private void setImageSize(String imageTag, String imageUrl, ReaderAttachment attachment) { + // TODO } /* * returns the basic content of the post tweaked for use here */ String getPostContent() { - if (mPost == null) { - return ""; - } else if (mPost.hasText()) { + 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) @@ -59,13 +123,7 @@ String getPostContent() { /* * returns the full content, including CSS, that will be shown in the WebView for this post */ - String getPostContentForWebView(Context context) { - if (mPost == null || context == null) { - return ""; - } - - String content = getPostContent(); - + private String getPostContentForWebView(String content) { StringBuilder sbHtml = new StringBuilder(""); // title isn't strictly necessary, but source is invalid html5 without one @@ -109,11 +167,8 @@ String getPostContentForWebView(Context context) { // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds if (canEnableJavaScript(mPost)) { - int videoWidth = DisplayUtils.pxToDp(context, - mResourceVars.fullSizeImageWidth - (mResourceVars.marginLarge * 2)); - int videoHeight = (int) (videoWidth * 0.5625f); - sbHtml.append(" iframe, embed { width: ").append(videoWidth).append("px !important;") - .append(" height: ").append(videoHeight).append("px !important; }"); + sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidth).append("px !important;") + .append(" height: ").append(mResourceVars.videoHeight).append("px !important; }"); } else { sbHtml.append(" iframe, embed { display: none; }"); } 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 index 6162ad27ea20..fd24ae4932d1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -23,6 +23,9 @@ class ReaderResourceVars { final int listMarginWidth; final int fullSizeImageWidth; + final int videoWidth; + final int videoHeight; + final int colorGreyExtraLight; final int mediumAnimTime; @@ -59,5 +62,8 @@ class ReaderResourceVars { imageWidth -= drawerWidth; } fullSizeImageWidth = imageWidth; + + videoWidth = DisplayUtils.pxToDp(context, fullSizeImageWidth - (marginLarge * 2)); + videoHeight = (int) (videoWidth * 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..a557890ad1ca 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,6 +13,10 @@ 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 static final int MIN_FEATURED_IMAGE_WIDTH = 500; @@ -36,6 +41,28 @@ public ReaderImageScanner(String contentOfPost, boolean isPrivate) { mIsPrivate = isPrivate; } + public void beginScan(ImageScanListener listener) { + if (listener == null) { + throw new IllegalArgumentException("ImageScanListener is required"); + } + + if (mContent == null || !mContent.contains(" Date: Thu, 28 Aug 2014 10:40:10 -0400 Subject: [PATCH 10/61] Matched images are now replaced with image tags that have height & width attributes set. --- .../android/ui/reader/ReaderPostRenderer.java | 90 ++++++++++++------- 1 file changed, 58 insertions(+), 32 deletions(-) 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 index 8180ed2d974e..3829758a264c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -23,6 +23,8 @@ public class ReaderPostRenderer { private final WeakReference mWeakWebView; private String mRenderContent; + private int mNumImages; + private int mNumMatchedImages; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (post == null) { @@ -39,7 +41,8 @@ public class ReaderPostRenderer { void beginRender() { // start with the basic content - mRenderContent = getPostContent(); + final String contentForScan = getPostContent(); + mRenderContent = contentForScan; // if there aren't any attachments, we're done if (!mPost.hasAttachments()) { @@ -47,46 +50,69 @@ void beginRender() { return; } + mNumImages = 0; + mNumMatchedImages = 0; + // start image scanner to find images, match them with attachments to get h/w ratio, then // replace h/w attributes with correct ones for display final ReaderAttachmentList attachments = mPost.getAttachments(); ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { @Override public void onImageFound(String imageTag, String imageUrl, int start, int end) { - AppLog.d(AppLog.T.READER, "reader renderer > found " + imageUrl); + mNumImages++; ReaderAttachment attach = attachments.get(imageUrl); if (attach != null) { - AppLog.d(AppLog.T.READER, "reader renderer > matched attachment " + imageUrl); - setImageSize(imageTag, imageUrl, attach); + mNumMatchedImages++; + setImageSize(imageTag, attach); } } @Override public void onScanCompleted() { - AppLog.d(AppLog.T.READER, "reader renderer > image scan completed"); + AppLog.i(AppLog.T.READER, + String.format("reader renderer > image scan completed, matched %d of %d images", + mNumMatchedImages, mNumImages)); endRender(); - }; + } }; - ReaderImageScanner scanner = new ReaderImageScanner(mRenderContent, mPost.isPrivate); + ReaderImageScanner scanner = new ReaderImageScanner(contentForScan, mPost.isPrivate); scanner.beginScan(imageListener); } - void endRender() { + private void endRender() { + // 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; } - AppLog.d(AppLog.T.READER, "reader renderer > rendering content"); - // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail // https://code.google.com/p/android/issues/detail?id=4401 String htmlContent = getPostContentForWebView(mRenderContent); webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } - private void setImageSize(String imageTag, String imageUrl, ReaderAttachment attachment) { - // TODO + /* + * called when image scanner finds an image and it can be matched with an attachment, + * use this to set the height/width of the image + */ + private void setImageSize(String imageTag, ReaderAttachment attachment) { + float ratio = attachment.getHWRatio(); + if (ratio == 0) { + AppLog.d(AppLog.T.READER, "reader renderer > empty image ratio"); + return; + } + + // construct new image tag + int width = mResourceVars.fullSizeImageWidth; + int height = (int)(width * ratio); + AppLog.d(AppLog.T.READER, String.format("reader renderer > image ratio, w=%d h=%d", width, height)); + String newImageTag + = String.format(""); sbHtml.append("") - .append(content) - .append(""); + .append(content) + .append(""); return sbHtml.toString(); } From 467c119f1a4af3986cd91917f6f9eef5908a24f6 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 11:08:42 -0400 Subject: [PATCH 11/61] Renderer now generates content in the background --- .../ui/reader/ReaderPostDetailFragment.java | 8 +- .../android/ui/reader/ReaderPostRenderer.java | 120 ++++++++---------- 2 files changed, 58 insertions(+), 70 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index ed1e0b53d799..251b41cc25d1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -69,7 +69,6 @@ public class ReaderPostDetailFragment extends Fragment private long mPostId; private long mBlogId; private ReaderPost mPost; - private ReaderPostRenderer mRenderer; private ReaderPostListType mPostListType; @@ -954,8 +953,10 @@ private boolean showPhotoViewer(String imageUrl, View sourceView, int startX, in return false; } + // must use getPostContent() so featured image added for display is seen + // by the photo viewer + String postContent = ReaderPostRenderer.getPostContent(mPost); boolean isPrivatePost = (mPost != null && mPost.isPrivate); - String postContent = (mRenderer != null ? mRenderer.getPostContent() : null); ReaderActivityLauncher.showReaderPhotoViewer( getActivity(), @@ -1089,8 +1090,7 @@ protected void onPostExecute(Boolean result) { mReaderWebView.getSettings().setJavaScriptEnabled(ReaderPostRenderer.canEnableJavaScript(mPost)); // render the post in the webView - mRenderer = new ReaderPostRenderer(mReaderWebView, mPost); - mRenderer.beginRender(); + new ReaderPostRenderer(mReaderWebView, mPost).beginRender(); txtTitle.setText(mPost.hasTitle() ? mPost.getTitle() : getString(R.string.reader_untitled_post)); 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 index 3829758a264c..5824337c5243 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -1,7 +1,7 @@ package org.wordpress.android.ui.reader; import android.net.Uri; -import android.text.TextUtils; +import android.os.Handler; import org.wordpress.android.models.ReaderAttachment; import org.wordpress.android.models.ReaderAttachmentList; @@ -14,7 +14,8 @@ import java.lang.ref.WeakReference; /** - * generates the HTML for displaying post detail content + * generates the HTML for showing post detail content - main purpose is to assign height/width + * attributes on image tags to match how we want them displayed */ public class ReaderPostRenderer { @@ -41,12 +42,11 @@ public class ReaderPostRenderer { void beginRender() { // start with the basic content - final String contentForScan = getPostContent(); - mRenderContent = contentForScan; + mRenderContent = getPostContent(mPost); // if there aren't any attachments, we're done if (!mPost.hasAttachments()) { - endRender(); + renderContent(mRenderContent); return; } @@ -55,30 +55,47 @@ void beginRender() { // start image scanner to find images, match them with attachments to get h/w ratio, then // replace h/w attributes with correct ones for display - final ReaderAttachmentList attachments = mPost.getAttachments(); - ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { + final Handler handler = new Handler(); + new Thread() { @Override - public void onImageFound(String imageTag, String imageUrl, int start, int end) { - mNumImages++; - ReaderAttachment attach = attachments.get(imageUrl); - if (attach != null) { - mNumMatchedImages++; - setImageSize(imageTag, attach); - } - } - @Override - public void onScanCompleted() { - AppLog.i(AppLog.T.READER, - String.format("reader renderer > image scan completed, matched %d of %d images", - mNumMatchedImages, mNumImages)); - endRender(); + public void run() { + final ReaderAttachmentList attachments = mPost.getAttachments(); + ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { + @Override + public void onImageFound(String imageTag, String imageUrl, int start, int end) { + mNumImages++; + ReaderAttachment attach = attachments.get(imageUrl); + // match only images, or else our video thumbnails might be replaced + if (attach != null && attach.isImage()) { + mNumMatchedImages++; + replaceImageTag(imageTag, attach); + } + } + @Override + public void onScanCompleted() { + AppLog.i(AppLog.T.READER, + String.format("reader renderer > image scan completed, matched %d of %d images", + mNumMatchedImages, mNumImages)); + final String htmlContent = getPostContentForWebView(mRenderContent); + handler.post(new Runnable() { + @Override + public void run() { + renderContent(htmlContent); + } + }); + } + }; + final String contentForScan = mRenderContent; + ReaderImageScanner scanner = new ReaderImageScanner(contentForScan, mPost.isPrivate); + scanner.beginScan(imageListener); } - }; - ReaderImageScanner scanner = new ReaderImageScanner(contentForScan, mPost.isPrivate); - scanner.beginScan(imageListener); + }.start(); } - private void endRender() { + /* + * called once the content is ready to be rendered in the webView + */ + private void renderContent(final String htmlContent) { // make sure webView is still valid (containing fragment may have been detached) ReaderWebView webView = mWeakWebView.get(); if (webView == null) { @@ -88,7 +105,6 @@ private void endRender() { // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail // https://code.google.com/p/android/issues/detail?id=4401 - String htmlContent = getPostContentForWebView(mRenderContent); webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } @@ -96,7 +112,7 @@ private void endRender() { * called when image scanner finds an image and it can be matched with an attachment, * use this to set the height/width of the image */ - private void setImageSize(String imageTag, ReaderAttachment attachment) { + private void replaceImageTag(String imageTag, ReaderAttachment attachment) { float ratio = attachment.getHWRatio(); if (ratio == 0) { AppLog.d(AppLog.T.READER, "reader renderer > empty image ratio"); @@ -106,7 +122,6 @@ private void setImageSize(String imageTag, ReaderAttachment attachment) { // construct new image tag int width = mResourceVars.fullSizeImageWidth; int height = (int)(width * ratio); - AppLog.d(AppLog.T.READER, String.format("reader renderer > image ratio, w=%d h=%d", width, height)); String newImageTag = String.format(" added featured image to content"); - content = String.format("

", mPost.getFeaturedImage()) + content = String.format("

", post.getFeaturedImage()) + content; } } return content; - } else if (mPost.hasFeaturedImage()) { + } else if (post.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()); + return String.format("

", post.getFeaturedImage()); } else { return ""; } @@ -232,32 +246,6 @@ private String getPostContentForWebView(String content) { return sbHtml.toString(); } - /* - * creates formatted div for passed video with passed (optional) thumbnail - */ - private static final String OVERLAY_IMG = "file:///android_asset/ic_reader_video_overlay.png"; - - private String makeVideoDiv(String videoUrl, String thumbnailUrl) { - if (TextUtils.isEmpty(videoUrl)) { - return ""; - } - - // sometimes we get src values like "//player.vimeo.com/video/70534716" - prefix these with http: - if (videoUrl.startsWith("//")) { - videoUrl = "http:" + videoUrl; - } - - int overlaySz = mResourceVars.videoOverlaySize / 2; - if (TextUtils.isEmpty(thumbnailUrl)) { - return String.format("
", videoUrl, overlaySz, overlaySz, OVERLAY_IMG); - } else { - return "
" - + String.format("", videoUrl, thumbnailUrl) - + String.format("", videoUrl, OVERLAY_IMG, overlaySz, overlaySz) - + "
"; - } - } - /* * javascript should only be enabled for wp blogs (not external feeds) */ From aaa5f70b4ebce694fc8463822ef4d5ca63351556 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 11:10:57 -0400 Subject: [PATCH 12/61] Removed unused ic_reader_video_overlay.png asset --- WordPress/src/main/assets/ic_reader_video_overlay.png | 1 - 1 file changed, 1 deletion(-) delete mode 120000 WordPress/src/main/assets/ic_reader_video_overlay.png diff --git a/WordPress/src/main/assets/ic_reader_video_overlay.png b/WordPress/src/main/assets/ic_reader_video_overlay.png deleted file mode 120000 index a58cc199483f..000000000000 --- a/WordPress/src/main/assets/ic_reader_video_overlay.png +++ /dev/null @@ -1 +0,0 @@ -../res/drawable-xhdpi/ic_reader_video_overlay.png \ No newline at end of file From 87b32b43ebfb8258f2f10d3469fc9b0be63a3494 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 11:29:05 -0400 Subject: [PATCH 13/61] Fixed missing close IMG tag --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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 index 5824337c5243..7cc3b2c99cf7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -122,8 +122,11 @@ private void replaceImageTag(String imageTag, ReaderAttachment attachment) { // construct new image tag int width = mResourceVars.fullSizeImageWidth; int height = (int)(width * ratio); + + //AppLog.d(AppLog.T.READER, String.format("reader renderer > ratio %f, width %d, height %d", ratio, width, height)); + String newImageTag - = String.format("", attachment.getUrl(), width, height); // replace existing tag with new one From c1f2dc0b581d1fdd2f8c5efce4275d10e0d417ef Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 11:41:04 -0400 Subject: [PATCH 14/61] Replaced images are now photon-ized --- .../android/ui/reader/ReaderPostRenderer.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 index 7cc3b2c99cf7..f79fef8dc2c2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -7,6 +7,7 @@ import org.wordpress.android.models.ReaderAttachmentList; 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.PhotonUtils; import org.wordpress.android.util.StringUtils; @@ -46,7 +47,7 @@ void beginRender() { // if there aren't any attachments, we're done if (!mPost.hasAttachments()) { - renderContent(mRenderContent); + renderContent(getPostContentForWebView(mRenderContent)); return; } @@ -123,11 +124,18 @@ private void replaceImageTag(String imageTag, ReaderAttachment attachment) { int width = mResourceVars.fullSizeImageWidth; int height = (int)(width * ratio); + final String newImageUrl; + if (mPost.isPrivate) { + newImageUrl = ReaderUtils.getPrivateImageForDisplay(attachment.getUrl(), width, height); + } else { + newImageUrl = PhotonUtils.getPhotonImageUrl(attachment.getUrl(), width, height); + } + //AppLog.d(AppLog.T.READER, String.format("reader renderer > ratio %f, width %d, height %d", ratio, width, height)); String newImageTag = String.format("", - attachment.getUrl(), width, height); + newImageUrl, width, height); // replace existing tag with new one mRenderContent = mRenderContent.replace(imageTag, newImageTag); From 6e22337886c94a0c5a85b765476fd6e22634a0e5 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 12:10:22 -0400 Subject: [PATCH 15/61] Added CSS background-color to full size images, removed size constraints from CSS, added baseUrl when loading content --- .../android/ui/reader/ReaderPostRenderer.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) 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 index f79fef8dc2c2..9a0129a79a19 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -106,7 +106,8 @@ private void renderContent(final String htmlContent) { // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail // https://code.google.com/p/android/issues/detail?id=4401 - webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); + String baseUrl = (mPost.hasBlogUrl() ? mPost.getBlogUrl() : null); + webView.loadDataWithBaseURL(baseUrl, htmlContent, "text/html", "UTF-8", null); } /* @@ -148,8 +149,7 @@ static String getPostContent(ReaderPost post) { if (post == null) { return ""; } else if (post.hasText()) { - // some content (such as Vimeo embeds) don't have "http:" before links, correct this here - String content = post.getText().replace("src=\"//", "src=\"http://"); + String content = post.getText(); if (post.hasFeaturedImage() && !PhotonUtils.isMshotsUrl(post.getFeaturedImage())) { // if the post has a featured image other than an mshot that's not in the content, // add it to the top of the content @@ -224,12 +224,8 @@ private String getPostContentForWebView(String content) { sbHtml.append(" iframe, embed { display: none; }"); } - // don't allow any image to be wider than the screen - sbHtml.append(" img { max-width: 100% !important; height: auto;}"); - - // show large wp images full-width (unnecessary in most cases since they'll already be at least - // as wide as the display, except maybe when viewed on a large landscape tablet) - sbHtml.append(" img.size-full, img.size-large { display: block; width: 100% !important; height: auto; }"); + // light grey background behind full-sized images so something appears while they're loading + sbHtml.append(" img.size-full { display: block; background-color: ").append(mResourceVars.greyExtraLightStr).append("; }"); // center medium-sized wp image sbHtml.append(" img.size-medium { display: block; margin-left: auto !important; margin-right: auto !important; }"); From 05ba41873f06aa248113cb4a2065dd1464a8a904 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 13:11:47 -0400 Subject: [PATCH 16/61] Removed baseUrl, apparently caused webView to stop firing onPageFinished (!) --- .../ui/reader/ReaderPostDetailFragment.java | 2 ++ .../android/ui/reader/ReaderPostRenderer.java | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 251b41cc25d1..8ee158b3cbc2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1216,6 +1216,8 @@ public void onPageFinished(WebView view, String url) { return; } + AppLog.i(T.READER, "onPageFinished"); + if (url != null && url.equals("about:blank")) { // brief delay before loading comments & likes to give a little time for page to render new Handler().postDelayed(new Runnable() { 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 index 9a0129a79a19..4a7c828fb30a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -106,8 +106,9 @@ private void renderContent(final String htmlContent) { // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail // https://code.google.com/p/android/issues/detail?id=4401 - String baseUrl = (mPost.hasBlogUrl() ? mPost.getBlogUrl() : null); - webView.loadDataWithBaseURL(baseUrl, htmlContent, "text/html", "UTF-8", null); + // 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); } /* @@ -149,7 +150,10 @@ static String getPostContent(ReaderPost post) { if (post == null) { return ""; } else if (post.hasText()) { - String content = post.getText(); + // some content (such as Vimeo embeds) don't have "http:" before links, correct this + // here - note that we can't fix this by passing a baseUrl in renderContent because + // that messages with webView's onPageFinished listener (no idea why) + String content = post.getText().replace("src=\"//", "src=\"http://"); if (post.hasFeaturedImage() && !PhotonUtils.isMshotsUrl(post.getFeaturedImage())) { // if the post has a featured image other than an mshot that's not in the content, // add it to the top of the content @@ -200,10 +204,9 @@ private String getPostContentForWebView(String content) { mResourceVars.marginSmall, mResourceVars.marginSmall)) .append(" p:first-child { margin-top: 0px; }"); - // add border, background color, and padding to pre blocks, and add overflow scrolling + // add background color and padding to pre blocks, and add overflow scrolling // so user can scroll the block if it's wider than the display sbHtml.append(" pre { overflow-x: scroll;") - .append(" border: 1px solid ").append(mResourceVars.greyLightStr).append("; ") .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append("; ") .append(" padding: ").append(mResourceVars.marginSmall).append("px; }"); @@ -224,8 +227,12 @@ private String getPostContentForWebView(String content) { sbHtml.append(" iframe, embed { display: none; }"); } - // light grey background behind full-sized images so something appears while they're loading - sbHtml.append(" img.size-full { display: block; background-color: ").append(mResourceVars.greyExtraLightStr).append("; }"); + // don't allow any image to be wider than the viewport + sbHtml.append(" img { max-width: 100% !important; height: auto; }"); + + // light grey background for large images so something appears while they're loading + sbHtml.append(" img.size-full, img.size-large { display: block;") + .append(" background-color ").append(mResourceVars.greyExtraLightStr).append("; }"); // center medium-sized wp image sbHtml.append(" img.size-medium { display: block; margin-left: auto !important; margin-right: auto !important; }"); @@ -246,7 +253,9 @@ private String getPostContentForWebView(String content) { .append(" div.tiled-gallery-caption { clear: both; }"); } - sbHtml.append("") + sbHtml.append(""); + + sbHtml.append("") .append(content) .append(""); From 4c431d78038c469b21d71953e0f06f1e2b91fa66 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 13:57:57 -0400 Subject: [PATCH 17/61] Switched to a StringBuilder for building render content --- .../ui/reader/ReaderPostDetailFragment.java | 2 - .../android/ui/reader/ReaderPostRenderer.java | 41 +++++++++++-------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 8ee158b3cbc2..251b41cc25d1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1216,8 +1216,6 @@ public void onPageFinished(WebView view, String url) { return; } - AppLog.i(T.READER, "onPageFinished"); - if (url != null && url.equals("about:blank")) { // brief delay before loading comments & likes to give a little time for page to render new Handler().postDelayed(new Runnable() { 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 index 4a7c828fb30a..623180f8bf38 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -15,8 +15,9 @@ import java.lang.ref.WeakReference; /** - * generates the HTML for showing post detail content - main purpose is to assign height/width - * attributes on image tags to match how we want them displayed + * generates and displays the HTML for showing post detail content - main purpose is to assign + * height/width attributes on image tags to match how we want them displayed - this avoids + * the webView content resizing as images are loaded */ public class ReaderPostRenderer { @@ -24,17 +25,17 @@ public class ReaderPostRenderer { private final ReaderPost mPost; private final WeakReference mWeakWebView; - private String mRenderContent; + private StringBuilder mRenderBuilder; private int mNumImages; private int mNumMatchedImages; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { - if (post == null) { - throw new IllegalArgumentException("ReaderPostRenderer requires a 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); @@ -43,19 +44,20 @@ public class ReaderPostRenderer { void beginRender() { // start with the basic content - mRenderContent = getPostContent(mPost); + final String content = getPostContent(mPost); // if there aren't any attachments, we're done if (!mPost.hasAttachments()) { - renderContent(getPostContentForWebView(mRenderContent)); + renderContent(getPostContentForWebView(content)); return; } mNumImages = 0; mNumMatchedImages = 0; + mRenderBuilder = new StringBuilder(content); - // start image scanner to find images, match them with attachments to get h/w ratio, then - // replace h/w attributes with correct ones for display + // start image scanner to find images, match them with the post's attachments so we can + // replace existing images with ones that have h/w set final Handler handler = new Handler(); new Thread() { @Override @@ -74,10 +76,10 @@ public void onImageFound(String imageTag, String imageUrl, int start, int end) { } @Override public void onScanCompleted() { - AppLog.i(AppLog.T.READER, + AppLog.d(AppLog.T.READER, String.format("reader renderer > image scan completed, matched %d of %d images", mNumMatchedImages, mNumImages)); - final String htmlContent = getPostContentForWebView(mRenderContent); + final String htmlContent = getPostContentForWebView(mRenderBuilder.toString()); handler.post(new Runnable() { @Override public void run() { @@ -86,8 +88,7 @@ public void run() { }); } }; - final String contentForScan = mRenderContent; - ReaderImageScanner scanner = new ReaderImageScanner(contentForScan, mPost.isPrivate); + ReaderImageScanner scanner = new ReaderImageScanner(content, mPost.isPrivate); scanner.beginScan(imageListener); } }.start(); @@ -115,10 +116,10 @@ private void renderContent(final String htmlContent) { * called when image scanner finds an image and it can be matched with an attachment, * use this to set the height/width of the image */ - private void replaceImageTag(String imageTag, ReaderAttachment attachment) { + private void replaceImageTag(final String imageTag, final ReaderAttachment attachment) { float ratio = attachment.getHWRatio(); if (ratio == 0) { - AppLog.d(AppLog.T.READER, "reader renderer > empty image ratio"); + AppLog.w(AppLog.T.READER, "reader renderer > empty image ratio"); return; } @@ -140,7 +141,13 @@ private void replaceImageTag(String imageTag, ReaderAttachment attachment) { newImageUrl, width, height); // replace existing tag with new one - mRenderContent = mRenderContent.replace(imageTag, 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); } /* From e82e522b86040d72b8a0cc46a0e368581095dfce Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 15:20:55 -0400 Subject: [PATCH 18/61] Now getting h/w from actual URL if it's from files.wordpress.com --- .../android/models/ReaderAttachment.java | 8 -- .../android/ui/reader/ReaderPostRenderer.java | 87 +++++++++---------- 2 files changed, 42 insertions(+), 53 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java index 1f364254b615..972df7b18887 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java @@ -54,14 +54,6 @@ public void setMimeType(String mimeType) { this.mimeType = StringUtils.notNullStr(mimeType); } - public float getHWRatio() { - if (width == 0 || height == 0) { - return 0; - } else { - return ((float) height / (float) width); - } - } - public boolean isImage() { return (mimeType != null && mimeType.startsWith("image")); } 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 index 623180f8bf38..a79a555436d3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -11,6 +11,7 @@ import org.wordpress.android.util.AppLog; import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.StringUtils; +import org.wordpress.android.util.UrlUtils; import java.lang.ref.WeakReference; @@ -24,10 +25,8 @@ public class ReaderPostRenderer { private final ReaderResourceVars mResourceVars; private final ReaderPost mPost; private final WeakReference mWeakWebView; - + private final ReaderAttachmentList mAttachments; private StringBuilder mRenderBuilder; - private int mNumImages; - private int mNumMatchedImages; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { @@ -40,46 +39,28 @@ public class ReaderPostRenderer { mPost = post; mWeakWebView = new WeakReference(webView); mResourceVars = new ReaderResourceVars(webView.getContext()); + mAttachments = (mPost.hasAttachments() ? mPost.getAttachments() : new ReaderAttachmentList()); } void beginRender() { // start with the basic content final String content = getPostContent(mPost); - - // if there aren't any attachments, we're done - if (!mPost.hasAttachments()) { - renderContent(getPostContentForWebView(content)); - return; - } - - mNumImages = 0; - mNumMatchedImages = 0; mRenderBuilder = new StringBuilder(content); - // start image scanner to find images, match them with the post's attachments so we can - // replace existing images with ones that have h/w set + // 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() { - final ReaderAttachmentList attachments = mPost.getAttachments(); ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { @Override public void onImageFound(String imageTag, String imageUrl, int start, int end) { - mNumImages++; - ReaderAttachment attach = attachments.get(imageUrl); - // match only images, or else our video thumbnails might be replaced - if (attach != null && attach.isImage()) { - mNumMatchedImages++; - replaceImageTag(imageTag, attach); - } + replaceImageTag(imageTag, imageUrl); } + @Override public void onScanCompleted() { - AppLog.d(AppLog.T.READER, - String.format("reader renderer > image scan completed, matched %d of %d images", - mNumMatchedImages, mNumImages)); - final String htmlContent = getPostContentForWebView(mRenderBuilder.toString()); + final String htmlContent = formatPostContentForWebView(mRenderBuilder.toString()); handler.post(new Runnable() { @Override public void run() { @@ -113,34 +94,50 @@ private void renderContent(final String htmlContent) { } /* - * called when image scanner finds an image and it can be matched with an attachment, - * use this to set the height/width of the image + * called when image scanner finds an image */ - private void replaceImageTag(final String imageTag, final ReaderAttachment attachment) { - float ratio = attachment.getHWRatio(); - if (ratio == 0) { - AppLog.w(AppLog.T.READER, "reader renderer > empty image ratio"); + private void replaceImageTag(final String imageTag, final String imageUrl) { + int origWidth; + int origHeight; + + // first try to get original image size from attachments, then try to get it from the url + // if it's an obvious WordPress image + ReaderAttachment attach = mAttachments.get(imageUrl); + if (attach != null && attach.isImage()) { + origWidth = attach.width; + origHeight = attach.height; + } else if (imageUrl.contains("files.wordpress.com")) { + Uri uri = Uri.parse(imageUrl.replace("&", "&")); + origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); + origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); + } else { return; } - // construct new image tag - int width = mResourceVars.fullSizeImageWidth; - int height = (int)(width * ratio); + int newWidth; + int newHeight; + if (origWidth > 0 && origHeight > 0) { + float ratio = ((float) origHeight / (float) origWidth); + newWidth = mResourceVars.fullSizeImageWidth; + newHeight = (int) (newWidth * ratio); + } else if (origWidth > 0) { + newWidth = mResourceVars.fullSizeImageWidth; + newHeight = 0; + } else { + return; + } - final String newImageUrl; + String newImageUrl; if (mPost.isPrivate) { - newImageUrl = ReaderUtils.getPrivateImageForDisplay(attachment.getUrl(), width, height); + newImageUrl = ReaderUtils.getPrivateImageForDisplay(UrlUtils.removeQuery(imageUrl), newWidth, newHeight); } else { - newImageUrl = PhotonUtils.getPhotonImageUrl(attachment.getUrl(), width, height); + newImageUrl = PhotonUtils.getPhotonImageUrl(UrlUtils.removeQuery(imageUrl), newWidth, newHeight); } - //AppLog.d(AppLog.T.READER, String.format("reader renderer > ratio %f, width %d, height %d", ratio, width, height)); - - String newImageTag - = String.format("", - newImageUrl, width, height); + String newImageTag = + String.format("", + newImageUrl, newWidth, newHeight); - // replace existing tag with new one int start = mRenderBuilder.indexOf(imageTag); if (start == -1) { AppLog.w(AppLog.T.READER, "reader renderer > image not found in builder"); @@ -185,7 +182,7 @@ static String getPostContent(ReaderPost post) { /* * returns the full content, including CSS, that will be shown in the WebView for this post */ - private String getPostContentForWebView(String content) { + private String formatPostContentForWebView(String content) { StringBuilder sbHtml = new StringBuilder(""); // title isn't strictly necessary, but source is invalid html5 without one From eb29613e6670f36d3537e870d803832d2ee0e8de Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 19:13:38 -0400 Subject: [PATCH 19/61] Added margin between full size images --- .../android/ui/reader/ReaderPostRenderer.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) 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 index a79a555436d3..a70009cddc07 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -16,9 +16,9 @@ import java.lang.ref.WeakReference; /** - * generates and displays the HTML for showing post detail content - main purpose is to assign - * height/width attributes on image tags to match how we want them displayed - this avoids - * the webView content resizing as images are loaded + * 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 */ public class ReaderPostRenderer { @@ -136,13 +136,12 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { String newImageTag = String.format("", - newImageUrl, newWidth, newHeight); + newImageUrl, newWidth, newHeight); 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); } @@ -164,7 +163,7 @@ static String getPostContent(ReaderPost post) { Uri uri = Uri.parse(post.getFeaturedImage()); String path = StringUtils.notNullStr(uri.getLastPathSegment()); if (!content.contains(path)) { - AppLog.d(AppLog.T.READER, "reader post detail > added featured image to content"); + AppLog.d(AppLog.T.READER, "reader renderer > added featured image to content"); content = String.format("

", post.getFeaturedImage()) + content; } @@ -234,9 +233,11 @@ private String formatPostContentForWebView(String content) { // don't allow any image to be wider than the viewport sbHtml.append(" img { max-width: 100% !important; height: auto; }"); - // light grey background for large images so something appears while they're loading + // light grey background for large images so something appears while they're loading, with a + // small bottom margin sbHtml.append(" img.size-full, img.size-large { display: block;") - .append(" background-color ").append(mResourceVars.greyExtraLightStr).append("; }"); + .append(" background-color ").append(mResourceVars.greyExtraLightStr).append(";") + .append(" margin-bottom: ").append(mResourceVars.marginSmall).append("px; }"); // center medium-sized wp image sbHtml.append(" img.size-medium { display: block; margin-left: auto !important; margin-right: auto !important; }"); From e180688c88b975c5e5471b1402c1574b281d9ff9 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 23:01:41 -0400 Subject: [PATCH 20/61] Centralized handling of private image URLs, featured images are now inserted with the correct h/w query params --- .../wordpress/android/models/ReaderPost.java | 6 +-- .../android/ui/reader/ReaderPhotoView.java | 10 +---- .../ui/reader/ReaderPostDetailFragment.java | 2 +- .../android/ui/reader/ReaderPostRenderer.java | 40 +++++++++++-------- .../android/ui/reader/ReaderResourceVars.java | 7 ++-- .../android/ui/reader/utils/ReaderUtils.java | 11 ++++- WordPress/src/main/res/values/dimens.xml | 1 - 7 files changed, 42 insertions(+), 35 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java index df1bf77ad477..d87cfdab20fb 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java @@ -454,12 +454,8 @@ public String getFeaturedImageForDisplay(int width, int height) { if (featuredImageForDisplay == null) { if (!hasFeaturedImage()) { featuredImageForDisplay = ""; - } else if (isPrivate) { - // images in private posts can't use photon, so handle separately - featuredImageForDisplay = ReaderUtils.getPrivateImageForDisplay(featuredImage, width, height); } else { - // not private, so set to correctly sized photon url - featuredImageForDisplay = PhotonUtils.getPhotonImageUrl(featuredImage, width, height); + featuredImageForDisplay = ReaderUtils.getResizedImageUrl(featuredImage, width, height, isPrivate); } } return featuredImageForDisplay; diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoView.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoView.java index e50c12ea19f5..34a4437b1585 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoView.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoView.java @@ -21,7 +21,6 @@ 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.PhotonUtils; import uk.co.senab.photoview.PhotoViewAttacher; @@ -77,13 +76,8 @@ public void setImageUrl(String imageUrl, boolean isPrivate, PhotoViewListener listener) { int loResWidth = (int) (hiResWidth * 0.10f); - if (isPrivate) { - mLoResImageUrl = ReaderUtils.getPrivateImageForDisplay(imageUrl, loResWidth, 0); - mHiResImageUrl = ReaderUtils.getPrivateImageForDisplay(imageUrl, hiResWidth, 0); - } else { - mLoResImageUrl = PhotonUtils.getPhotonImageUrl(imageUrl, loResWidth, 0); - mHiResImageUrl = PhotonUtils.getPhotonImageUrl(imageUrl, hiResWidth, 0); - } + mLoResImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, loResWidth, 0, isPrivate); + mHiResImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, hiResWidth, 0, isPrivate); mPhotoViewListener = listener; loadLoResImage(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 251b41cc25d1..6d36f07dadad 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -955,7 +955,7 @@ private boolean showPhotoViewer(String imageUrl, View sourceView, int startX, in // must use getPostContent() so featured image added for display is seen // by the photo viewer - String postContent = ReaderPostRenderer.getPostContent(mPost); + String postContent = ReaderPostRenderer.getPostContent(mPost, null); boolean isPrivatePost = (mPost != null && mPost.isPrivate); ReaderActivityLauncher.showReaderPhotoViewer( 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 index a70009cddc07..0ea6d7578bcd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -11,7 +11,6 @@ import org.wordpress.android.util.AppLog; import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.StringUtils; -import org.wordpress.android.util.UrlUtils; import java.lang.ref.WeakReference; @@ -44,7 +43,7 @@ public class ReaderPostRenderer { void beginRender() { // start with the basic content - final String content = getPostContent(mPost); + final String content = getPostContent(mPost, mResourceVars); mRenderBuilder = new StringBuilder(content); // start image scanner to find images so we can replace them with ones that have h/w set @@ -127,13 +126,7 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { return; } - String newImageUrl; - if (mPost.isPrivate) { - newImageUrl = ReaderUtils.getPrivateImageForDisplay(UrlUtils.removeQuery(imageUrl), newWidth, newHeight); - } else { - newImageUrl = PhotonUtils.getPhotonImageUrl(UrlUtils.removeQuery(imageUrl), newWidth, newHeight); - } - + String newImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, newWidth, newHeight, mPost.isPrivate); String newImageTag = String.format("", newImageUrl, newWidth, newHeight); @@ -149,13 +142,11 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { /* * returns the basic content of the post tweaked for use here */ - static String getPostContent(ReaderPost post) { + static String getPostContent(ReaderPost post, ReaderResourceVars resourceVars) { if (post == null) { return ""; } else if (post.hasText()) { - // some content (such as Vimeo embeds) don't have "http:" before links, correct this - // here - note that we can't fix this by passing a baseUrl in renderContent because - // that messages with webView's onPageFinished listener (no idea why) + // some content (such as Vimeo embeds) don't have "http:" before links String content = post.getText().replace("src=\"//", "src=\"http://"); if (post.hasFeaturedImage() && !PhotonUtils.isMshotsUrl(post.getFeaturedImage())) { // if the post has a featured image other than an mshot that's not in the content, @@ -164,20 +155,37 @@ static String getPostContent(ReaderPost post) { String path = StringUtils.notNullStr(uri.getLastPathSegment()); if (!content.contains(path)) { AppLog.d(AppLog.T.READER, "reader renderer > added featured image to content"); - content = String.format("

", post.getFeaturedImage()) - + content; + content = getFeaturedImageHtml(post, resourceVars) + content; } } return content; } else if (post.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("

", post.getFeaturedImage()); + return getFeaturedImageHtml(post, resourceVars); } else { return ""; } } + /* + * returns the HTML to use when inserting a featured image into the rendered content + */ + private static String getFeaturedImageHtml(ReaderPost post, ReaderResourceVars resourceVars) { + String imageUrl; + if (resourceVars != null) { + imageUrl = ReaderUtils.getResizedImageUrl( + post.getFeaturedImage(), + resourceVars.fullSizeImageWidth, + resourceVars.featuredImageHeight, + post.isPrivate); + } else { + imageUrl = post.getFeaturedImage(); + } + + return String.format("

", imageUrl); + } + /* * returns the full content, including CSS, that will be shown in the WebView for this post */ 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 index fd24ae4932d1..10fe3f5aaf58 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -9,19 +9,20 @@ import org.wordpress.android.util.HtmlUtils; /* - * class which holds all resource-based variables used by this fragment + * class which holds all resource-based variables used when rendering post detail */ class ReaderResourceVars { final int displayWidth; final int actionBarHeight; final int likeAvatarSize; - final int videoOverlaySize; final int marginLarge; final int marginSmall; final int marginExtraSmall; final int listMarginWidth; + final int fullSizeImageWidth; + final int featuredImageHeight; final int videoWidth; final int videoHeight; @@ -39,7 +40,7 @@ class ReaderResourceVars { displayWidth = DisplayUtils.getDisplayPixelWidth(context); actionBarHeight = DisplayUtils.getActionBarHeight(context); likeAvatarSize = resources.getDimensionPixelSize(R.dimen.avatar_sz_small); - videoOverlaySize = resources.getDimensionPixelSize(R.dimen.reader_video_overlay_size); + featuredImageHeight = resources.getDimensionPixelSize(R.dimen.reader_featured_image_height); marginLarge = resources.getDimensionPixelSize(R.dimen.margin_large); marginSmall = resources.getDimensionPixelSize(R.dimen.margin_small); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java index 050691db2374..c207641f6853 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java @@ -12,6 +12,7 @@ import android.widget.TextView; import org.wordpress.android.R; +import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.UrlUtils; import java.util.List; @@ -130,11 +131,19 @@ public static Bitmap createBitmapFromView(View view) { } } + public static String getResizedImageUrl(final String imageUrl, int width, int height, boolean isPrivate) { + if (isPrivate) { + return getPrivateImageForDisplay(imageUrl, width, height); + } else { + return PhotonUtils.getPhotonImageUrl(imageUrl, width, height); + } + } + /* * use this to request a reduced size image from a private post - images in private posts can't * use photon but these are usually wp images so they support the h= and w= query params */ - public static String getPrivateImageForDisplay(final String imageUrl, int width, int height) { + private static String getPrivateImageForDisplay(final String imageUrl, int width, int height) { if (TextUtils.isEmpty(imageUrl)) { return ""; } 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 - 48dp 12dp @dimen/margin_large From e674135f361044f4a95db553967e397658fab07c Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 28 Aug 2014 23:39:26 -0400 Subject: [PATCH 21/61] Inserted featured image now include width & height attributes --- .../android/ui/reader/ReaderPostRenderer.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) 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 index 0ea6d7578bcd..e6c1064bad53 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -154,7 +154,6 @@ static String getPostContent(ReaderPost post, ReaderResourceVars resourceVars) { Uri uri = Uri.parse(post.getFeaturedImage()); String path = StringUtils.notNullStr(uri.getLastPathSegment()); if (!content.contains(path)) { - AppLog.d(AppLog.T.READER, "reader renderer > added featured image to content"); content = getFeaturedImageHtml(post, resourceVars) + content; } } @@ -172,18 +171,20 @@ static String getPostContent(ReaderPost post, ReaderResourceVars resourceVars) { * returns the HTML to use when inserting a featured image into the rendered content */ private static String getFeaturedImageHtml(ReaderPost post, ReaderResourceVars resourceVars) { - String imageUrl; if (resourceVars != null) { - imageUrl = ReaderUtils.getResizedImageUrl( - post.getFeaturedImage(), - resourceVars.fullSizeImageWidth, - resourceVars.featuredImageHeight, - post.isPrivate); + int width = resourceVars.fullSizeImageWidth; + int height = resourceVars.featuredImageHeight; + String imageUrl = ReaderUtils.getResizedImageUrl( + post.getFeaturedImage(), + width, + height, + post.isPrivate); + AppLog.d(AppLog.T.READER, "reader renderer > featured image added to content"); + return String.format("", + imageUrl, width, height); } else { - imageUrl = post.getFeaturedImage(); + return String.format("", post.getFeaturedImage()); } - - return String.format("

", imageUrl); } /* From 073b0b344c2a1b80254bb2409e6fe8121e8f0f8c Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 00:06:22 -0400 Subject: [PATCH 22/61] Featured image is now skipped when replacing scanned images --- .../wordpress/android/ui/reader/ReaderPostRenderer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 index e6c1064bad53..61eb6103fa1f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -99,6 +99,12 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { int origWidth; int origHeight; + // skip featured images inserted by getFeaturedImageHtml() since they already + // have their height & width set + if (imageUrl.contains("featured image")) { + return; + } + // first try to get original image size from attachments, then try to get it from the url // if it's an obvious WordPress image ReaderAttachment attach = mAttachments.get(imageUrl); @@ -180,7 +186,7 @@ private static String getFeaturedImageHtml(ReaderPost post, ReaderResourceVars r height, post.isPrivate); AppLog.d(AppLog.T.READER, "reader renderer > featured image added to content"); - return String.format("", + return String.format("featured image", imageUrl, width, height); } else { return String.format("", post.getFeaturedImage()); From 6515923b8bc42806dfa876c39f30ab2c94e0fcb7 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 08:38:30 -0400 Subject: [PATCH 23/61] Featured image now only appears above content if there are no other images in the content --- .../android/ui/reader/ReaderPostRenderer.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) 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 index 61eb6103fa1f..be04ff915a27 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -93,18 +93,19 @@ private void renderContent(final String htmlContent) { } /* - * called when image scanner finds an image + * called when image scanner finds an image, replaces the image tag with one that + * has height & width set if possible */ private void replaceImageTag(final String imageTag, final String imageUrl) { - int origWidth; - int origHeight; - // skip featured images inserted by getFeaturedImageHtml() since they already // have their height & width set - if (imageUrl.contains("featured image")) { + if (imageUrl.contains("featured-image")) { return; } + int origWidth; + int origHeight; + // first try to get original image size from attachments, then try to get it from the url // if it's an obvious WordPress image ReaderAttachment attach = mAttachments.get(imageUrl); @@ -145,31 +146,32 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { mRenderBuilder.replace(start, start + imageTag.length(), newImageTag); } + /* + * 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 static boolean shouldAddFeaturedImage(ReaderPost post) { + return post != null + && post.hasFeaturedImage() + && !post.getText().contains(" added featured image"); + content = getFeaturedImageHtml(post, resourceVars) + content; } return content; - } else if (post.hasFeaturedImage()) { - // some photo blogs have posts with empty content but still have a featured image, so - // use the featured image as the content - return getFeaturedImageHtml(post, resourceVars); - } else { - return ""; } } @@ -185,8 +187,8 @@ private static String getFeaturedImageHtml(ReaderPost post, ReaderResourceVars r width, height, post.isPrivate); - AppLog.d(AppLog.T.READER, "reader renderer > featured image added to content"); - return String.format("featured image", + // add unused class 'featured-image' so it can be detected by replaceImageTag() + return String.format("", imageUrl, width, height); } else { return String.format("", post.getFeaturedImage()); From 22d877acf028491162cb56fdeeb57d72169d2725 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 09:47:58 -0400 Subject: [PATCH 24/61] Performance tweaks and fixes to ensure photo viewer is passed the actual rendered HTML content --- .../ui/reader/ReaderPhotoViewerActivity.java | 48 +++++++----- .../ui/reader/ReaderPostDetailFragment.java | 9 +-- .../android/ui/reader/ReaderPostRenderer.java | 78 +++++++++---------- 3 files changed, 72 insertions(+), 63 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoViewerActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoViewerActivity.java index 6451112c7c36..814c195a77ef 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoViewerActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPhotoViewerActivity.java @@ -16,6 +16,7 @@ import org.wordpress.android.ui.reader.ReaderViewPagerTransformer.TransformType; import org.wordpress.android.ui.reader.models.ReaderImageList; import org.wordpress.android.ui.reader.utils.ReaderImageScanner; +import org.wordpress.android.util.AppLog; import javax.annotation.Nonnull; @@ -68,26 +69,35 @@ public void onPageSelected(int position) { } private void loadImageList() { - new Thread() { - @Override - public void run() { - // parse list of images from content that was (optionally) passed to - // this activity, and make sure the list includes the passed url - ReaderImageScanner scanner = new ReaderImageScanner(mContent, mIsPrivate); - final ReaderImageList imageList = scanner.getImageList(); - if (!TextUtils.isEmpty(mInitialImageUrl) && !imageList.hasImageUrl(mInitialImageUrl)) { - imageList.addImageUrl(0, mInitialImageUrl); - } - runOnUiThread(new Runnable() { - @Override - public void run() { - if (!isFinishing()) { - setImageList(imageList, mInitialImageUrl); - } - } - }); + // content will be empty unless this was called by ReaderPostDetailFragment to show + // a list of images in a post (in which case, it's the content of the post) + if (TextUtils.isEmpty(mContent)) { + final ReaderImageList imageList = new ReaderImageList(mIsPrivate); + if (!TextUtils.isEmpty(mInitialImageUrl)) { + imageList.add(mInitialImageUrl); } - }.start(); + setImageList(imageList, mInitialImageUrl); + } else { + // parse images from content and make sure the list includes the passed url + new Thread() { + @Override + public void run() { + final ReaderImageList imageList = new ReaderImageScanner(mContent, mIsPrivate).getImageList(); + if (!TextUtils.isEmpty(mInitialImageUrl) && !imageList.hasImageUrl(mInitialImageUrl)) { + AppLog.w(AppLog.T.READER, "reader photo viewer > initial image not in list"); + imageList.addImageUrl(0, mInitialImageUrl); + } + runOnUiThread(new Runnable() { + @Override + public void run() { + if (!isFinishing()) { + setImageList(imageList, mInitialImageUrl); + } + } + }); + } + }.start(); + } } private void setImageList(ReaderImageList imageList, String initialImageUrl) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 6d36f07dadad..cfe95911649c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -69,7 +69,7 @@ public class ReaderPostDetailFragment extends Fragment private long mPostId; private long mBlogId; private ReaderPost mPost; - + private ReaderPostRenderer mRenderer; private ReaderPostListType mPostListType; private ViewGroup mLayoutIcons; @@ -953,9 +953,7 @@ private boolean showPhotoViewer(String imageUrl, View sourceView, int startX, in return false; } - // must use getPostContent() so featured image added for display is seen - // by the photo viewer - String postContent = ReaderPostRenderer.getPostContent(mPost, null); + String postContent = (mRenderer != null ? mRenderer.getRenderedHtml() : null); boolean isPrivatePost = (mPost != null && mPost.isPrivate); ReaderActivityLauncher.showReaderPhotoViewer( @@ -1090,7 +1088,8 @@ protected void onPostExecute(Boolean result) { mReaderWebView.getSettings().setJavaScriptEnabled(ReaderPostRenderer.canEnableJavaScript(mPost)); // render the post in the webView - new ReaderPostRenderer(mReaderWebView, mPost).beginRender(); + mRenderer = new ReaderPostRenderer(mReaderWebView, mPost); + mRenderer.beginRender(); txtTitle.setText(mPost.hasTitle() ? mPost.getTitle() : getString(R.string.reader_untitled_post)); 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 index be04ff915a27..66c8a4b28da5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -25,7 +25,9 @@ public class ReaderPostRenderer { private final ReaderPost mPost; private final WeakReference mWeakWebView; private final ReaderAttachmentList mAttachments; + private StringBuilder mRenderBuilder; + private String mRenderedHtml; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { @@ -42,9 +44,7 @@ public class ReaderPostRenderer { } void beginRender() { - // start with the basic content - final String content = getPostContent(mPost, mResourceVars); - mRenderBuilder = new StringBuilder(content); + 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(); @@ -60,15 +60,16 @@ public void onImageFound(String imageTag, String imageUrl, int start, int end) { @Override public void onScanCompleted() { final String htmlContent = formatPostContentForWebView(mRenderBuilder.toString()); + mRenderBuilder = null; handler.post(new Runnable() { @Override public void run() { - renderContent(htmlContent); + renderHtmlContent(htmlContent); } }); } }; - ReaderImageScanner scanner = new ReaderImageScanner(content, mPost.isPrivate); + ReaderImageScanner scanner = new ReaderImageScanner(mRenderBuilder.toString(), mPost.isPrivate); scanner.beginScan(imageListener); } }.start(); @@ -77,7 +78,9 @@ public void run() { /* * called once the content is ready to be rendered in the webView */ - private void renderContent(final String htmlContent) { + 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) { @@ -93,8 +96,8 @@ private void renderContent(final String htmlContent) { } /* - * called when image scanner finds an image, replaces the image tag with one that - * has height & width set if possible + * called when image scanner finds an image, tries to replaces the image tag with one that + * has height & width attributes set */ private void replaceImageTag(final String imageTag, final String imageUrl) { // skip featured images inserted by getFeaturedImageHtml() since they already @@ -151,48 +154,45 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { * post's content - when this is the case, the featured image is inserted at * the top of the content */ - private static boolean shouldAddFeaturedImage(ReaderPost post) { - return post != null - && post.hasFeaturedImage() - && !post.getText().contains(" added featured image"); - content = getFeaturedImageHtml(post, resourceVars) + content; - } - return content; + private String getPostContent() { + // some content (such as Vimeo embeds) don't have "http:" before links + String content = mPost.getText().replace("src=\"//", "src=\"http://"); + if (shouldAddFeaturedImage()) { + AppLog.w(AppLog.T.READER, "reader renderer > 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 static String getFeaturedImageHtml(ReaderPost post, ReaderResourceVars resourceVars) { - if (resourceVars != null) { - int width = resourceVars.fullSizeImageWidth; - int height = resourceVars.featuredImageHeight; - String imageUrl = ReaderUtils.getResizedImageUrl( - post.getFeaturedImage(), - width, - height, - post.isPrivate); - // add unused class 'featured-image' so it can be detected by replaceImageTag() - return String.format("", - imageUrl, width, height); - } else { - return String.format("", post.getFeaturedImage()); - } + private String getFeaturedImageHtml() { + String imageUrl = ReaderUtils.getResizedImageUrl( + mPost.getFeaturedImage(), + mResourceVars.fullSizeImageWidth, + mResourceVars.featuredImageHeight, + mPost.isPrivate); + + // add unused class 'featured-image' so it can be detected by replaceImageTag() + return String.format("", + imageUrl, mResourceVars.fullSizeImageWidth, mResourceVars.featuredImageHeight); } /* From 5743cccd6eede4803518da525c284ee7a017a9b9 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 11:24:43 -0400 Subject: [PATCH 25/61] Removed separate attachment table, now storing attachment JSON with the post. --- .../datasets/ReaderAttachmentTable.java | 107 ------------------ .../android/datasets/ReaderDatabase.java | 11 +- .../android/datasets/ReaderPostTable.java | 16 ++- .../android/models/ReaderAttachment.java | 27 ++--- .../android/models/ReaderAttachmentList.java | 21 +++- .../wordpress/android/models/ReaderPost.java | 46 ++++---- .../android/ui/reader/ReaderPostRenderer.java | 17 ++- 7 files changed, 75 insertions(+), 170 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java deleted file mode 100644 index 574ba72cb5c6..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderAttachmentTable.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.wordpress.android.datasets; - -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteStatement; - -import org.wordpress.android.models.ReaderAttachment; -import org.wordpress.android.models.ReaderAttachmentList; -import org.wordpress.android.models.ReaderPost; -import org.wordpress.android.models.ReaderPostList; -import org.wordpress.android.util.SqlUtils; - -/** - * stores attachments for reader posts - */ -public class ReaderAttachmentTable { - protected static void createTables(SQLiteDatabase db) { - db.execSQL("CREATE TABLE tbl_attachments (" - + " post_id INTEGER," - + " blog_id INTEGER," - + " attachment_id INTEGER," - + " url TEXT NOT NULL," - + " mime_type TEXT NOT NULL," - + " width INTEGER DEFAULT 0," - + " height INTEGER DEFAULT 0," - + " PRIMARY KEY (post_id, blog_id, attachment_id)" - + ")"); - } - - protected static void dropTables(SQLiteDatabase db) { - db.execSQL("DROP TABLE IF EXISTS tbl_attachments"); - } - - /* - * purge table of attachments to posts that no longer exist - */ - protected static int purge(SQLiteDatabase db) { - return db.delete("tbl_attachments", "post_id NOT IN (SELECT DISTINCT post_id FROM tbl_posts)", null); - } - - public static ReaderAttachmentList getAttachmentsForPost(long blogId, long postId) { - String[] args = {Long.toString(blogId), Long.toString(postId)}; - Cursor c = ReaderDatabase.getReadableDb().rawQuery("SELECT * FROM tbl_attachments WHERE blog_id=? AND post_id=?", args); - try { - ReaderAttachmentList attachments = new ReaderAttachmentList(); - if (c.moveToFirst()) { - do { - attachments.add(getAttachmentFromCursor(c)); - } while (c.moveToNext()); - } - return attachments; - } finally { - SqlUtils.closeCursor(c); - } - } - - public static void saveAttachmentsForPosts(ReaderPostList posts) { - if (posts == null || posts.size() == 0) { - return; - } - - SQLiteDatabase db = ReaderDatabase.getWritableDb(); - SQLiteStatement stmt = db.compileStatement( - "INSERT INTO tbl_attachments" - + " (blog_id, post_id, attachment_id, url, mime_type, width, height)" - + " VALUES (?1,?2,?3,?4,?5,?6,?7)"); - try { - for (ReaderPost post : posts) { - if (post.hasAttachments()) { - // first delete all attachments for this post - String[] args = {Long.toString(post.blogId), Long.toString(post.postId)}; - db.delete("tbl_attachments", "blog_id=? AND post_id=?", args); - - // now insert the passed ones - stmt.bindLong(1, post.blogId); - stmt.bindLong(2, post.postId); - for (ReaderAttachment attach : post.getAttachments()) { - stmt.bindLong (3, attach.attachmentId); - stmt.bindString(4, attach.getUrl()); - stmt.bindString(5, attach.getMimeType()); - stmt.bindLong (6, attach.width); - stmt.bindLong (7, attach.height); - stmt.execute(); - } - } - } - } finally { - SqlUtils.closeStatement(stmt); - } - } - - private static ReaderAttachment getAttachmentFromCursor(Cursor c) { - ReaderAttachment attach = new ReaderAttachment(); - - attach.blogId = c.getLong(c.getColumnIndex("blog_id")); - attach.postId = c.getLong(c.getColumnIndex("post_id")); - attach.attachmentId = c.getLong(c.getColumnIndex("attachment_id")); - - attach.setUrl(c.getString(c.getColumnIndex("url"))); - attach.setMimeType(c.getString(c.getColumnIndex("mime_type"))); - - attach.height = c.getInt(c.getColumnIndex("height")); - attach.width = c.getInt(c.getColumnIndex("width")); - - return attach; - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java index 3a3d495110eb..e94203ba982d 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderDatabase.java @@ -19,7 +19,7 @@ */ public class ReaderDatabase extends SQLiteOpenHelper { protected static final String DB_NAME = "wpreader.db"; - private static final int DB_VERSION = 84; + private static final int DB_VERSION = 85; /* * version history @@ -41,6 +41,7 @@ public class ReaderDatabase extends SQLiteOpenHelper { * 82 - added idx_posts_timestamp to tbl_posts * 83 - removed tag_list from tbl_posts * 84 - added tbl_attachments + * 85 - removed tbl_attachments, added attachments_json to tbl_posts */ /* @@ -116,7 +117,6 @@ private void createAllTables(SQLiteDatabase db) { ReaderUserTable.createTables(db); ReaderThumbnailTable.createTables(db); ReaderBlogTable.createTables(db); - ReaderAttachmentTable.createTables(db); } private void dropAllTables(SQLiteDatabase db) { @@ -127,7 +127,6 @@ private void dropAllTables(SQLiteDatabase db) { ReaderUserTable.dropTables(db); ReaderThumbnailTable.dropTables(db); ReaderBlogTable.dropTables(db); - ReaderAttachmentTable.dropTables(db); } /* @@ -180,12 +179,6 @@ private static void purge() { if (numTagsPurged > 0) { AppLog.i(T.READER, String.format("%d tags purged", numTagsPurged)); } - - // purge unattached post attachments - int numAttachPurged = ReaderAttachmentTable.purge(db); - if (numAttachPurged > 0) { - AppLog.i(T.READER, String.format("%d attachments purged", numAttachPurged)); - } } db.setTransactionSuccessful(); } finally { diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java index fb0369182b2b..c1d9bc01414e 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderPostTable.java @@ -47,7 +47,8 @@ public class ReaderPostTable { + "primary_tag," // 26 + "secondary_tag," // 27 + "is_likes_enabled," // 28 - + "is_sharing_enabled"; // 29 + + "is_sharing_enabled," // 29 + + "attachments_json"; // 30 protected static void createTables(SQLiteDatabase db) { @@ -81,6 +82,7 @@ protected static void createTables(SQLiteDatabase db) { + " secondary_tag TEXT," + " is_likes_enabled INTEGER DEFAULT 0," + " is_sharing_enabled INTEGER DEFAULT 0," + + " attachments_json TEXT," + " PRIMARY KEY (post_id, blog_id)" + ")"); db.execSQL("CREATE INDEX idx_posts_timestamp ON tbl_posts(timestamp)"); @@ -373,7 +375,7 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { SQLiteStatement stmtPosts = db.compileStatement( "INSERT OR REPLACE INTO tbl_posts (" + COLUMN_NAMES - + ") VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29)"); + + ") VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9,?10,?11,?12,?13,?14,?15,?16,?17,?18,?19,?20,?21,?22,?23,?24,?25,?26,?27,?28,?29,?30)"); SQLiteStatement stmtTags = db.compileStatement( "INSERT OR REPLACE INTO tbl_post_tags (post_id, blog_id, pseudo_id, tag_name, tag_type) VALUES (?1,?2,?3,?4,?5)"); @@ -410,6 +412,7 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { stmtPosts.bindString(27, post.getSecondaryTag()); stmtPosts.bindLong (28, SqlUtils.boolToSql(post.isLikesEnabled)); stmtPosts.bindLong (29, SqlUtils.boolToSql(post.isSharingEnabled)); + stmtPosts.bindString(30, post.getAttachmentsJson()); stmtPosts.execute(); } @@ -427,9 +430,6 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { } } - // save attachments for posts that have any - ReaderAttachmentTable.saveAttachmentsForPosts(posts); - db.setTransactionSuccessful(); } finally { @@ -563,6 +563,8 @@ private static class PostColumnIndexes { private final int idx_is_likes_enabled; private final int idx_is_sharing_enabled; + private final int idx_attachments_json; + private PostColumnIndexes(Cursor c) { if (c == null) throw new IllegalArgumentException("PostColumnIndexes > null cursor"); @@ -603,6 +605,8 @@ private PostColumnIndexes(Cursor c) { idx_is_likes_enabled = c.getColumnIndex("is_likes_enabled"); idx_is_sharing_enabled = c.getColumnIndex("is_sharing_enabled"); + + idx_attachments_json = c.getColumnIndex("attachments_json"); } } @@ -655,7 +659,7 @@ private static ReaderPost getPostFromCursor(Cursor c, PostColumnIndexes cols) { post.isLikesEnabled = SqlUtils.sqlToBool(c.getInt(cols.idx_is_likes_enabled)); post.isSharingEnabled = SqlUtils.sqlToBool(c.getInt(cols.idx_is_sharing_enabled)); - post.setAttachments(ReaderAttachmentTable.getAttachmentsForPost(post.blogId, post.postId)); + post.setAttachmentsJson(c.getString(cols.idx_attachments_json)); return post; } diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java index 972df7b18887..0a719e411a3d 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java @@ -6,39 +6,33 @@ import org.wordpress.android.util.UrlUtils; public class ReaderAttachment { - public long postId; - public long blogId; public long attachmentId; + public int width; + public int height; private String url; private String mimeType; - public int width; - public int height; - - public static ReaderAttachment fromJson(long blogId, long postId, JSONObject json) { + public static ReaderAttachment fromJson(JSONObject json) { ReaderAttachment attach = new ReaderAttachment(); if (json == null) { return attach; } - attach.blogId = blogId; - attach.postId = postId; attach.attachmentId = json.optLong("ID"); - - attach.setMimeType(JSONUtil.getString(json, "mime_type")); - attach.setUrl(JSONUtil.getString(json, "URL")); - attach.width = json.optInt("width"); attach.height = json.optInt("height"); + attach.mimeType = JSONUtil.getString(json, "mime_type"); + attach.setUrl(JSONUtil.getString(json, "URL")); + return attach; } public String getUrl() { return StringUtils.notNullStr(url); } - public void setUrl(String url) { + private void setUrl(String url) { // always store normalized URLs without a query string if (url != null) { this.url = UrlUtils.normalizeUrl(UrlUtils.removeQuery(url)); @@ -47,13 +41,6 @@ public void setUrl(String url) { } } - public String getMimeType() { - return StringUtils.notNullStr(mimeType); - } - public void setMimeType(String mimeType) { - this.mimeType = StringUtils.notNullStr(mimeType); - } - public boolean isImage() { return (mimeType != null && mimeType.startsWith("image")); } diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java index 73a98fc89c51..a8a42956ea40 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java @@ -1,6 +1,10 @@ package org.wordpress.android.models; +import android.text.TextUtils; + +import org.json.JSONException; import org.json.JSONObject; +import org.wordpress.android.util.AppLog; import org.wordpress.android.util.UrlUtils; import java.util.ArrayList; @@ -8,7 +12,20 @@ public class ReaderAttachmentList extends ArrayList { - public static ReaderAttachmentList fromJson(long blogId, long postId, JSONObject json) { + public static ReaderAttachmentList fromJsonString(String strJson) { + if (TextUtils.isEmpty(strJson)) { + return new ReaderAttachmentList(); + } + + try { + return fromJson(new JSONObject(strJson)); + } catch (JSONException e) { + AppLog.e(AppLog.T.READER, e); + return new ReaderAttachmentList(); + } + } + + private static ReaderAttachmentList fromJson(JSONObject json) { ReaderAttachmentList attachments = new ReaderAttachmentList(); if (json == null) { return attachments; @@ -21,7 +38,7 @@ public static ReaderAttachmentList fromJson(long blogId, long postId, JSONObject while (it.hasNext()) { JSONObject jsonAttach = json.optJSONObject(it.next()); - attachments.add(ReaderAttachment.fromJson(blogId, postId, jsonAttach)); + attachments.add(ReaderAttachment.fromJson(jsonAttach)); } return attachments; diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java index d87cfdab20fb..824aed8edcc1 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java @@ -52,7 +52,7 @@ public class ReaderPost { public boolean isLikesEnabled; public boolean isSharingEnabled; // currently unused - private ReaderAttachmentList attachments; + private String attachmentsJson; public static ReaderPost fromJson(JSONObject json) { if (json == null) { @@ -158,7 +158,10 @@ public static ReaderPost fromJson(JSONObject json) { assignTagsFromJson(post, json.optJSONObject("tags")); // parse the attachments - assignAttachmentsFromJson(post, json.optJSONObject("attachments")); + JSONObject jsonAttachments = json.optJSONObject("attachments"); + if (jsonAttachments != null) { + post.attachmentsJson = jsonAttachments.toString(); + } // the single-post sites/$site/posts/$post endpoint returns all site metadata // under meta/data/site (assuming ?meta=site was added to the request) @@ -173,10 +176,6 @@ public static ReaderPost fromJson(JSONObject json) { return post; } - private static void assignAttachmentsFromJson(ReaderPost post, JSONObject jsonAttachments) { - post.setAttachments(ReaderAttachmentList.fromJson(post.blogId, post.postId, jsonAttachments)); - } - /* * assigns author-related info to the passed post from the passed JSON "author" object */ @@ -375,6 +374,26 @@ public void setSecondaryTag(String tagName) { } } + /* + * attachments are stored as the actual JSON to avoid having a separate table for + * them, may need to revisit this if/when attachments become more important + */ + public String getAttachmentsJson() { + return StringUtils.notNullStr(attachmentsJson); + } + public void setAttachmentsJson(String json) { + attachmentsJson = StringUtils.notNullStr(json); + mAttachments = null; + } + + private transient ReaderAttachmentList mAttachments; + public ReaderAttachmentList getAttachments() { + if (mAttachments == null) { + mAttachments = ReaderAttachmentList.fromJsonString(attachmentsJson); + } + return mAttachments; + } + public boolean hasText() { return !TextUtils.isEmpty(text); } @@ -425,21 +444,6 @@ public boolean isWP() { return !isExternal; } - public boolean hasAttachments() { - return (attachments != null && attachments.size() > 0); - } - public ReaderAttachmentList getAttachments() { - return attachments; - } - public void setAttachments(ReaderAttachmentList attachments) { - if (attachments != null) { - this.attachments = (ReaderAttachmentList) attachments.clone(); - } else { - this.attachments = new ReaderAttachmentList(); - } - } - - /**** * the following are transient variables - not stored in the db or returned in the json - whose * sole purpose is to cache commonly-used values for the post that speeds up using them inside 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 index 66c8a4b28da5..4dbfc75952e6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -24,10 +24,10 @@ public class ReaderPostRenderer { private final ReaderResourceVars mResourceVars; private final ReaderPost mPost; private final WeakReference mWeakWebView; - private final ReaderAttachmentList mAttachments; private StringBuilder mRenderBuilder; private String mRenderedHtml; + private ReaderAttachmentList mAttachments; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { @@ -40,7 +40,6 @@ public class ReaderPostRenderer { mPost = post; mWeakWebView = new WeakReference(webView); mResourceVars = new ReaderResourceVars(webView.getContext()); - mAttachments = (mPost.hasAttachments() ? mPost.getAttachments() : new ReaderAttachmentList()); } void beginRender() { @@ -51,6 +50,8 @@ void beginRender() { new Thread() { @Override public void run() { + mAttachments = mPost.getAttachments(); + ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { @Override public void onImageFound(String imageTag, String imageUrl, int start, int end) { @@ -111,16 +112,21 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { // first try to get original image size from attachments, then try to get it from the url // if it's an obvious WordPress image - ReaderAttachment attach = mAttachments.get(imageUrl); + ReaderAttachment attach = (mAttachments != null ? mAttachments.get(imageUrl) : null); if (attach != null && attach.isImage()) { origWidth = attach.width; origHeight = attach.height; + AppLog.d(AppLog.T.READER, "reader renderer > setting size from attachment"); } else if (imageUrl.contains("files.wordpress.com")) { Uri uri = Uri.parse(imageUrl.replace("&", "&")); origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); + if (origWidth > 0) { + AppLog.d(AppLog.T.READER, "reader renderer > setting size from query params"); + } } else { - return; + origWidth = 0; + origHeight = 0; } int newWidth; @@ -133,6 +139,7 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { newWidth = mResourceVars.fullSizeImageWidth; newHeight = 0; } else { + AppLog.d(AppLog.T.READER, "reader renderer > no size for " + imageUrl); return; } @@ -167,7 +174,7 @@ private String getPostContent() { // some content (such as Vimeo embeds) don't have "http:" before links String content = mPost.getText().replace("src=\"//", "src=\"http://"); if (shouldAddFeaturedImage()) { - AppLog.w(AppLog.T.READER, "reader renderer > added featured image"); + AppLog.d(AppLog.T.READER, "reader renderer > added featured image"); content = getFeaturedImageHtml() + content; } return content; From 2b365fe4e5a1112017b75022c67682d14a7d9465 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 13:27:11 -0400 Subject: [PATCH 26/61] Removed AppLog debug messages from renderer --- .../android/ui/reader/ReaderPostRenderer.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) 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 index 4dbfc75952e6..36f9e8e7c12d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -19,7 +19,7 @@ * 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 */ -public class ReaderPostRenderer { +class ReaderPostRenderer { private final ReaderResourceVars mResourceVars; private final ReaderPost mPost; @@ -116,17 +116,12 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { if (attach != null && attach.isImage()) { origWidth = attach.width; origHeight = attach.height; - AppLog.d(AppLog.T.READER, "reader renderer > setting size from attachment"); } else if (imageUrl.contains("files.wordpress.com")) { Uri uri = Uri.parse(imageUrl.replace("&", "&")); origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); - if (origWidth > 0) { - AppLog.d(AppLog.T.READER, "reader renderer > setting size from query params"); - } } else { - origWidth = 0; - origHeight = 0; + return; } int newWidth; @@ -139,7 +134,6 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { newWidth = mResourceVars.fullSizeImageWidth; newHeight = 0; } else { - AppLog.d(AppLog.T.READER, "reader renderer > no size for " + imageUrl); return; } From ed82bb8b02d6a32d8093bfad32ad7c5db87efcd1 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 13:46:57 -0400 Subject: [PATCH 27/61] Added hint about whether content contains IMG tags to ReaderImageScanner --- .../ui/reader/utils/ReaderImageScanner.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) 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 a557890ad1ca..ca289747222e 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 @@ -19,6 +19,7 @@ public static interface ImageScanListener { } 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 @@ -39,14 +40,18 @@ public static interface ImageScanListener { public ReaderImageScanner(String contentOfPost, boolean isPrivate) { mContent = contentOfPost; mIsPrivate = isPrivate; + mContentContainsImages = mContent != null && mContent.contains(" Date: Fri, 29 Aug 2014 22:06:27 -0400 Subject: [PATCH 28/61] Fixed bug that caused featured image to be replaced --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index 36f9e8e7c12d..a35f075481fb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -103,7 +103,7 @@ private void renderHtmlContent(final String htmlContent) { private void replaceImageTag(final String imageTag, final String imageUrl) { // skip featured images inserted by getFeaturedImageHtml() since they already // have their height & width set - if (imageUrl.contains("featured-image")) { + if (imageTag.contains("featured-image")) { return; } @@ -121,7 +121,8 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); } else { - return; + origWidth = 0; + origHeight = 0; } int newWidth; @@ -134,6 +135,7 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { newWidth = mResourceVars.fullSizeImageWidth; newHeight = 0; } else { + AppLog.d(AppLog.T.READER, "reader renderer > no size for " + imageUrl); return; } From fb135d7dfd9725ee2eebbe02b99c351d0150f9ba Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 23:33:10 -0400 Subject: [PATCH 29/61] Logic for getting image h/w from query params moved to separate function --- .../ui/reader/ReaderPostDetailFragment.java | 1 + .../android/ui/reader/ReaderPostRenderer.java | 36 ++++++++++++++----- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index cfe95911649c..57aa19cfa009 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1004,6 +1004,7 @@ private void postFailed() { 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); 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 index a35f075481fb..346221a6c9e8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -96,6 +96,29 @@ private void renderHtmlContent(final String htmlContent) { webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } + private static class ImageSize { + final int width; + final int height; + ImageSize(int width, int height) { + this.width = width; + this.height = height; + } + } + + /* + * returns the image size by examining the query params on the passed image url + */ + private ImageSize getImageSizeFromImageUrl(final String imageUrl) { + if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { + Uri uri = Uri.parse(imageUrl.replace("&", "&")); + return new ImageSize( + StringUtils.stringToInt(uri.getQueryParameter("w")), + StringUtils.stringToInt(uri.getQueryParameter("h"))); + } else { + return null; + } + } + /* * called when image scanner finds an image, tries to replaces the image tag with one that * has height & width attributes set @@ -107,22 +130,17 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { return; } + // first try to get original image size from attachments, then try to get it from the url int origWidth; int origHeight; - - // first try to get original image size from attachments, then try to get it from the url - // if it's an obvious WordPress image ReaderAttachment attach = (mAttachments != null ? mAttachments.get(imageUrl) : null); if (attach != null && attach.isImage()) { origWidth = attach.width; origHeight = attach.height; - } else if (imageUrl.contains("files.wordpress.com")) { - Uri uri = Uri.parse(imageUrl.replace("&", "&")); - origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); - origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); } else { - origWidth = 0; - origHeight = 0; + ImageSize size = getImageSizeFromImageUrl(imageUrl); + origWidth = (size != null ? size.width : 0); + origHeight = (size != null ? size.height : 0); } int newWidth; From df2d721daf94ad690e387802856e5f67b7c4706d Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 29 Aug 2014 23:50:07 -0400 Subject: [PATCH 30/61] Reverted previous commit and optimized logic to get h/w from query params --- .../android/ui/reader/ReaderPostRenderer.java | 37 ++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) 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 index 346221a6c9e8..e123f9ff2bee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -96,31 +96,8 @@ private void renderHtmlContent(final String htmlContent) { webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } - private static class ImageSize { - final int width; - final int height; - ImageSize(int width, int height) { - this.width = width; - this.height = height; - } - } - - /* - * returns the image size by examining the query params on the passed image url - */ - private ImageSize getImageSizeFromImageUrl(final String imageUrl) { - if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { - Uri uri = Uri.parse(imageUrl.replace("&", "&")); - return new ImageSize( - StringUtils.stringToInt(uri.getQueryParameter("w")), - StringUtils.stringToInt(uri.getQueryParameter("h"))); - } else { - return null; - } - } - /* - * called when image scanner finds an image, tries to replaces the image tag with one that + * called when image scanner finds an image, tries to replace the image tag with one that * has height & width attributes set */ private void replaceImageTag(final String imageTag, final String imageUrl) { @@ -130,17 +107,20 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { return; } - // first try to get original image size from attachments, then try to get it from the url + // first try to get original image size from attachments, then try to get it from the + // query params if it's an obvious wp image int origWidth; int origHeight; ReaderAttachment attach = (mAttachments != null ? mAttachments.get(imageUrl) : null); if (attach != null && attach.isImage()) { origWidth = attach.width; origHeight = attach.height; + } else if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { + Uri uri = Uri.parse(imageUrl.replace("&", "&")); + origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); + origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); } else { - ImageSize size = getImageSizeFromImageUrl(imageUrl); - origWidth = (size != null ? size.width : 0); - origHeight = (size != null ? size.height : 0); + return; } int newWidth; @@ -153,7 +133,6 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { newWidth = mResourceVars.fullSizeImageWidth; newHeight = 0; } else { - AppLog.d(AppLog.T.READER, "reader renderer > no size for " + imageUrl); return; } From c040d77464648193417ab837fc9a6bc4c1fe8299 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sat, 30 Aug 2014 08:28:09 -0400 Subject: [PATCH 31/61] Removed ReaderAttachment/ReaderAttachmentList models, added HashMap of attachment sizes to ReaderPostRenderer for fast lookup. --- .../android/models/ReaderAttachment.java | 47 -------- .../android/models/ReaderAttachmentList.java | 61 ----------- .../wordpress/android/models/ReaderPost.java | 8 -- .../android/ui/reader/ReaderPostRenderer.java | 100 ++++++++++++++---- 4 files changed, 80 insertions(+), 136 deletions(-) delete mode 100644 WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java delete mode 100644 WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java deleted file mode 100644 index 0a719e411a3d..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachment.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.wordpress.android.models; - -import org.json.JSONObject; -import org.wordpress.android.util.JSONUtil; -import org.wordpress.android.util.StringUtils; -import org.wordpress.android.util.UrlUtils; - -public class ReaderAttachment { - public long attachmentId; - public int width; - public int height; - - private String url; - private String mimeType; - - public static ReaderAttachment fromJson(JSONObject json) { - ReaderAttachment attach = new ReaderAttachment(); - if (json == null) { - return attach; - } - - attach.attachmentId = json.optLong("ID"); - attach.width = json.optInt("width"); - attach.height = json.optInt("height"); - - attach.mimeType = JSONUtil.getString(json, "mime_type"); - attach.setUrl(JSONUtil.getString(json, "URL")); - - return attach; - } - - public String getUrl() { - return StringUtils.notNullStr(url); - } - private void setUrl(String url) { - // always store normalized URLs without a query string - if (url != null) { - this.url = UrlUtils.normalizeUrl(UrlUtils.removeQuery(url)); - } else { - this.url = ""; - } - } - - public boolean isImage() { - return (mimeType != null && mimeType.startsWith("image")); - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java deleted file mode 100644 index a8a42956ea40..000000000000 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderAttachmentList.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.wordpress.android.models; - -import android.text.TextUtils; - -import org.json.JSONException; -import org.json.JSONObject; -import org.wordpress.android.util.AppLog; -import org.wordpress.android.util.UrlUtils; - -import java.util.ArrayList; -import java.util.Iterator; - -public class ReaderAttachmentList extends ArrayList { - - public static ReaderAttachmentList fromJsonString(String strJson) { - if (TextUtils.isEmpty(strJson)) { - return new ReaderAttachmentList(); - } - - try { - return fromJson(new JSONObject(strJson)); - } catch (JSONException e) { - AppLog.e(AppLog.T.READER, e); - return new ReaderAttachmentList(); - } - } - - private static ReaderAttachmentList fromJson(JSONObject json) { - ReaderAttachmentList attachments = new ReaderAttachmentList(); - if (json == null) { - return attachments; - } - - Iterator it = json.keys(); - if (!it.hasNext()) { - return attachments; - } - - while (it.hasNext()) { - JSONObject jsonAttach = json.optJSONObject(it.next()); - attachments.add(ReaderAttachment.fromJson(jsonAttach)); - } - - return attachments; - } - - public ReaderAttachment get(final String imageUrl) { - if (imageUrl == null) { - return null; - } - - String normUrl = UrlUtils.normalizeUrl(UrlUtils.removeQuery(imageUrl)); - for (ReaderAttachment attachment: this) { - if (normUrl.equals(attachment.getUrl())) { - return attachment; - } - } - - return null; - } -} diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java index 824aed8edcc1..313298d7ff28 100644 --- a/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java +++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderPost.java @@ -383,16 +383,8 @@ public String getAttachmentsJson() { } public void setAttachmentsJson(String json) { attachmentsJson = StringUtils.notNullStr(json); - mAttachments = null; } - private transient ReaderAttachmentList mAttachments; - public ReaderAttachmentList getAttachments() { - if (mAttachments == null) { - mAttachments = ReaderAttachmentList.fromJsonString(attachmentsJson); - } - return mAttachments; - } public boolean hasText() { return !TextUtils.isEmpty(text); 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 index e123f9ff2bee..b4472b07b037 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -2,17 +2,22 @@ import android.net.Uri; import android.os.Handler; +import android.text.TextUtils; -import org.wordpress.android.models.ReaderAttachment; -import org.wordpress.android.models.ReaderAttachmentList; +import org.json.JSONException; +import org.json.JSONObject; 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.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 @@ -27,7 +32,7 @@ class ReaderPostRenderer { private StringBuilder mRenderBuilder; private String mRenderedHtml; - private ReaderAttachmentList mAttachments; + private ImageSizeMap mAttachments; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { @@ -50,7 +55,7 @@ void beginRender() { new Thread() { @Override public void run() { - mAttachments = mPost.getAttachments(); + mAttachments = new ImageSizeMap(mPost.getAttachmentsJson()); ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { @Override @@ -96,6 +101,23 @@ private void renderHtmlContent(final String htmlContent) { webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } + /* + * attempts to return the image size from the passed url - first tries to get size from + * attachments, then tries to get it from the query params if it's an obvious wp image + */ + private ImageSize getImageSize(final String imageUrl) { + ImageSize size = (mAttachments != null ? mAttachments.getAttachmentSize(imageUrl) : null); + if (size != null) { + return size; + } else if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { + Uri uri = Uri.parse(imageUrl.replace("&", "&")); + return new ImageSize( + StringUtils.stringToInt(uri.getQueryParameter("w")), + StringUtils.stringToInt(uri.getQueryParameter("h"))); + } else { + return null; + } + } /* * called when image scanner finds an image, tries to replace the image tag with one that * has height & width attributes set @@ -107,29 +129,18 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { return; } - // first try to get original image size from attachments, then try to get it from the - // query params if it's an obvious wp image - int origWidth; - int origHeight; - ReaderAttachment attach = (mAttachments != null ? mAttachments.get(imageUrl) : null); - if (attach != null && attach.isImage()) { - origWidth = attach.width; - origHeight = attach.height; - } else if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { - Uri uri = Uri.parse(imageUrl.replace("&", "&")); - origWidth = StringUtils.stringToInt(uri.getQueryParameter("w")); - origHeight = StringUtils.stringToInt(uri.getQueryParameter("h")); - } else { + ImageSize origSize = getImageSize(imageUrl); + if (origSize == null) { return; } int newWidth; int newHeight; - if (origWidth > 0 && origHeight > 0) { - float ratio = ((float) origHeight / (float) origWidth); + if (origSize.width > 0 && origSize.height > 0) { + float ratio = ((float) origSize.height / (float) origSize.width); newWidth = mResourceVars.fullSizeImageWidth; newHeight = (int) (newWidth * ratio); - } else if (origWidth > 0) { + } else if (origSize.width > 0) { newWidth = mResourceVars.fullSizeImageWidth; newHeight = 0; } else { @@ -290,4 +301,53 @@ private String formatPostContentForWebView(String content) { static boolean canEnableJavaScript(ReaderPost post) { return (post != null && post.isWP()); } + + /* + * hash map of sizes of attachments in the current post for quick lookup + */ + 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()); + String mimeType = JSONUtil.getString(json, "mime_type"); + if (mimeType.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; + } + } } From 37a40a340d177c9f19393e40da229d22848737a1 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sat, 30 Aug 2014 12:36:29 -0400 Subject: [PATCH 32/61] HashMap of attachment sizes is now built only when needed --- .../android/ui/reader/ReaderPostRenderer.java | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) 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 index b4472b07b037..53d43cb78806 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -32,7 +32,7 @@ class ReaderPostRenderer { private StringBuilder mRenderBuilder; private String mRenderedHtml; - private ImageSizeMap mAttachments; + private ImageSizeMap mAttachmentSizes; ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { @@ -55,8 +55,6 @@ void beginRender() { new Thread() { @Override public void run() { - mAttachments = new ImageSizeMap(mPost.getAttachmentsJson()); - ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() { @Override public void onImageFound(String imageTag, String imageUrl, int start, int end) { @@ -101,23 +99,6 @@ private void renderHtmlContent(final String htmlContent) { webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null); } - /* - * attempts to return the image size from the passed url - first tries to get size from - * attachments, then tries to get it from the query params if it's an obvious wp image - */ - private ImageSize getImageSize(final String imageUrl) { - ImageSize size = (mAttachments != null ? mAttachments.getAttachmentSize(imageUrl) : null); - if (size != null) { - return size; - } else if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { - Uri uri = Uri.parse(imageUrl.replace("&", "&")); - return new ImageSize( - StringUtils.stringToInt(uri.getQueryParameter("w")), - StringUtils.stringToInt(uri.getQueryParameter("h"))); - } else { - return null; - } - } /* * called when image scanner finds an image, tries to replace the image tag with one that * has height & width attributes set @@ -295,15 +276,41 @@ private String formatPostContentForWebView(String content) { return sbHtml.toString(); } + /* + * attempts to return the image size from the passed url - first tries to get size from + * attachments, then tries to get it from the query params if it's an obvious wp image + */ + private ImageSize getImageSize(final String imageUrl) { + ImageSize size = getAttachmentSize(imageUrl); + if (size != null) { + return size; + } else if (imageUrl.contains("files.wordpress.com") && imageUrl.contains("w=")) { + Uri uri = Uri.parse(imageUrl.replace("&", "&")); + return new ImageSize( + StringUtils.stringToInt(uri.getQueryParameter("w")), + StringUtils.stringToInt(uri.getQueryParameter("h"))); + } else { + return null; + } + } + + private ImageSize getAttachmentSize(final String imageUrl) { + if (mAttachmentSizes == null) { + mAttachmentSizes = new ImageSizeMap(mPost.getAttachmentsJson()); + } + return mAttachmentSizes.getAttachmentSize(imageUrl); + } + /* * javascript should only be enabled for wp blogs (not external feeds) */ static boolean canEnableJavaScript(ReaderPost post) { - return (post != null && post.isWP()); + return post != null && post.isWP(); } /* - * hash map of sizes of attachments in the current post for quick lookup + * 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) { From ba25aedbb707bebe25242477fca53fb1bb5def68 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sat, 30 Aug 2014 23:32:33 -0400 Subject: [PATCH 33/61] Added logic to get image sizes from resize= query param --- .../android/ui/reader/ReaderPostRenderer.java | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) 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 index 53d43cb78806..d0f7dca91122 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -104,12 +104,6 @@ private void renderHtmlContent(final String htmlContent) { * has height & width attributes set */ private void replaceImageTag(final String imageTag, final String imageUrl) { - // skip featured images inserted by getFeaturedImageHtml() since they already - // have their height & width set - if (imageTag.contains("featured-image")) { - return; - } - ImageSize origSize = getImageSize(imageUrl); if (origSize == null) { return; @@ -182,9 +176,7 @@ private String getFeaturedImageHtml() { mResourceVars.featuredImageHeight, mPost.isPrivate); - // add unused class 'featured-image' so it can be detected by replaceImageTag() - return String.format("", - imageUrl, mResourceVars.fullSizeImageWidth, mResourceVars.featuredImageHeight); + return String.format("", imageUrl); } /* @@ -276,31 +268,46 @@ private String formatPostContentForWebView(String content) { return sbHtml.toString(); } - /* - * attempts to return the image size from the passed url - first tries to get size from - * attachments, then tries to get it from the query params if it's an obvious wp image - */ private ImageSize getImageSize(final String imageUrl) { - ImageSize size = getAttachmentSize(imageUrl); + ImageSize size = getImageSizeFromAttachments(imageUrl); if (size != null) { return size; - } else if (imageUrl.contains("files.wordpress.com") && 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("?")) { + return getImageSizeFromQueryParams(imageUrl); } else { return null; } } - private ImageSize getAttachmentSize(final String imageUrl) { + 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) { + int width = StringUtils.stringToInt(sizes[0]); + int height = StringUtils.stringToInt(sizes[1]); + return new ImageSize(width, height); + } + } + } + + return null; + } + /* * javascript should only be enabled for wp blogs (not external feeds) */ From 0e39c8f1d8ea18964efcdcc125f88af51b451b8e Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sun, 31 Aug 2014 10:14:35 -0400 Subject: [PATCH 34/61] Appended "px" to dimen resource variables for clarity --- .../ui/reader/ReaderPostDetailFragment.java | 4 +- .../android/ui/reader/ReaderPostRenderer.java | 28 +++++------ .../android/ui/reader/ReaderResourceVars.java | 46 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 57aa19cfa009..a69664ab7222 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -244,7 +244,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa if (isFullScreenSupported()) { mListView.setOnScrollDirectionListener(this); mListView.setOnScrollListener(this); - ReaderUtils.addListViewHeader(mListView, mResourceVars.actionBarHeight); + ReaderUtils.addListViewHeader(mListView, mResourceVars.actionBarHeightPx); } // add post detail as header to listView - must be done before setting adapter @@ -1123,7 +1123,7 @@ 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); 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 index d0f7dca91122..acd8c5a59ef1 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -113,10 +113,10 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { int newHeight; if (origSize.width > 0 && origSize.height > 0) { float ratio = ((float) origSize.height / (float) origSize.width); - newWidth = mResourceVars.fullSizeImageWidth; + newWidth = mResourceVars.fullSizeImageWidthPx; newHeight = (int) (newWidth * ratio); } else if (origSize.width > 0) { - newWidth = mResourceVars.fullSizeImageWidth; + newWidth = mResourceVars.fullSizeImageWidthPx; newHeight = 0; } else { return; @@ -172,8 +172,8 @@ String getRenderedHtml() { private String getFeaturedImageHtml() { String imageUrl = ReaderUtils.getResizedImageUrl( mPost.getFeaturedImage(), - mResourceVars.fullSizeImageWidth, - mResourceVars.featuredImageHeight, + mResourceVars.fullSizeImageWidthPx, + mResourceVars.featuredImageHeightPx, mPost.isPrivate); return String.format("", imageUrl); @@ -205,18 +205,18 @@ private String formatPostContentForWebView(String content) { // use a consistent top/bottom margin for paragraphs, with no top margin for the first one sbHtml.append(String.format(" p { margin-top: %dpx; margin-bottom: %dpx; }", - mResourceVars.marginSmall, mResourceVars.marginSmall)) + mResourceVars.marginSmallPx, mResourceVars.marginSmallPx)) .append(" p:first-child { margin-top: 0px; }"); // add background color and padding to pre blocks, and add overflow scrolling // so user can scroll the block if it's wider than the display sbHtml.append(" pre { overflow-x: scroll;") .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append("; ") - .append(" padding: ").append(mResourceVars.marginSmall).append("px; }"); + .append(" padding: ").append(mResourceVars.marginSmallPx).append("px; }"); // add a left border to blockquotes - sbHtml.append(" blockquote { margin-left: ").append(mResourceVars.marginSmall).append("px; ") - .append(" padding-left: ").append(mResourceVars.marginSmall).append("px; ") + sbHtml.append(" blockquote { margin-left: ").append(mResourceVars.marginSmallPx).append("px; ") + .append(" padding-left: ").append(mResourceVars.marginSmallPx).append("px; ") .append(" border-left: 3px solid ").append(mResourceVars.greyLightStr).append("; }"); // show links in the same color they are elsewhere in the app @@ -225,8 +225,8 @@ private String formatPostContentForWebView(String content) { // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds if (canEnableJavaScript(mPost)) { - sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidth).append("px !important;") - .append(" height: ").append(mResourceVars.videoHeight).append("px !important; }"); + sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidthPx).append("px !important;") + .append(" height: ").append(mResourceVars.videoHeightPx).append("px !important; }"); } else { sbHtml.append(" iframe, embed { display: none; }"); } @@ -238,7 +238,7 @@ private String formatPostContentForWebView(String content) { // small bottom margin sbHtml.append(" img.size-full, img.size-large { display: block;") .append(" background-color ").append(mResourceVars.greyExtraLightStr).append(";") - .append(" margin-bottom: ").append(mResourceVars.marginSmall).append("px; }"); + .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }"); // center medium-sized wp image sbHtml.append(" img.size-medium { display: block; margin-left: auto !important; margin-right: auto !important; }"); @@ -248,13 +248,13 @@ private String formatPostContentForWebView(String content) { // params with ones that make images fit the width of the listView item, then adjust the // relevant CSS classes so their height/width are auto, and add top/bottom margin to images if (content.contains("tiled-gallery-item")) { - String widthParam = "w=" + Integer.toString(mResourceVars.fullSizeImageWidth); + String widthParam = "w=" + Integer.toString(mResourceVars.fullSizeImageWidthPx); content = content.replaceAll("w=[0-9]+", widthParam).replaceAll("h=[0-9]+", ""); sbHtml.append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") .append(" div.tiled-gallery-item img { ") .append(" width: auto !important; height: auto !important;") - .append(" margin-top: ").append(mResourceVars.marginExtraSmall).append("px; ") - .append(" margin-bottom: ").append(mResourceVars.marginExtraSmall).append("px; ") + .append(" margin-top: ").append(mResourceVars.marginExtraSmallPx).append("px; ") + .append(" margin-bottom: ").append(mResourceVars.marginExtraSmallPx).append("px; ") .append(" }") .append(" div.tiled-gallery-caption { clear: both; }"); } 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 index 10fe3f5aaf58..fcc5e7ebda65 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -12,20 +12,20 @@ * class which holds all resource-based variables used when rendering post detail */ class ReaderResourceVars { - final int displayWidth; - final int actionBarHeight; - final int likeAvatarSize; + final int displayWidthPx; + final int actionBarHeightPx; + final int likeAvatarSizePx; - final int marginLarge; - final int marginSmall; - final int marginExtraSmall; - final int listMarginWidth; + final int marginLargePx; + final int marginSmallPx; + final int marginExtraSmallPx; + final int listMarginWidthPx; - final int fullSizeImageWidth; - final int featuredImageHeight; + final int fullSizeImageWidthPx; + final int featuredImageHeightPx; - final int videoWidth; - final int videoHeight; + final int videoWidthPx; + final int videoHeightPx; final int colorGreyExtraLight; final int mediumAnimTime; @@ -37,15 +37,15 @@ class ReaderResourceVars { ReaderResourceVars(Context context) { Resources resources = context.getResources(); - displayWidth = DisplayUtils.getDisplayPixelWidth(context); - actionBarHeight = DisplayUtils.getActionBarHeight(context); - likeAvatarSize = resources.getDimensionPixelSize(R.dimen.avatar_sz_small); - featuredImageHeight = resources.getDimensionPixelSize(R.dimen.reader_featured_image_height); + 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); - marginLarge = resources.getDimensionPixelSize(R.dimen.margin_large); - marginSmall = resources.getDimensionPixelSize(R.dimen.margin_small); - marginExtraSmall = resources.getDimensionPixelSize(R.dimen.margin_extra_small); - listMarginWidth = resources.getDimensionPixelOffset(R.dimen.reader_list_margin); + 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); @@ -54,7 +54,7 @@ class ReaderResourceVars { greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light); greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light); - int imageWidth = displayWidth - (listMarginWidth * 2); + int imageWidth = displayWidthPx - (listMarginWidthPx * 2); boolean hasStaticMenuDrawer = (context instanceof WPActionBarActivity) && (((WPActionBarActivity) context).isStaticMenuDrawer()); @@ -62,9 +62,9 @@ class ReaderResourceVars { int drawerWidth = resources.getDimensionPixelOffset(R.dimen.menu_drawer_width); imageWidth -= drawerWidth; } - fullSizeImageWidth = imageWidth; + fullSizeImageWidthPx = imageWidth; - videoWidth = DisplayUtils.pxToDp(context, fullSizeImageWidth - (marginLarge * 2)); - videoHeight = (int) (videoWidth * 0.5625f); + videoWidthPx = DisplayUtils.pxToDp(context, fullSizeImageWidthPx - (marginLargePx * 2)); + videoHeightPx = (int) (videoWidthPx * 0.5625f); } } From dc7b713aa31dd966cbc595e861107da7bbc37ffa Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sun, 31 Aug 2014 22:01:27 -0400 Subject: [PATCH 35/61] Enabling JavaScript moved from detail fragment to renderer --- .../android/ui/reader/ReaderPostDetailFragment.java | 3 --- .../android/ui/reader/ReaderPostRenderer.java | 10 +++++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index a69664ab7222..c8252e2d58c8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1085,9 +1085,6 @@ protected void onPostExecute(Boolean result) { return; } - // enable JavaScript in the webView if it's safe to do so - mReaderWebView.getSettings().setJavaScriptEnabled(ReaderPostRenderer.canEnableJavaScript(mPost)); - // render the post in the webView mRenderer = new ReaderPostRenderer(mReaderWebView, mPost); mRenderer.beginRender(); 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 index acd8c5a59ef1..9908a24ae533 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -45,6 +45,10 @@ class ReaderPostRenderer { mPost = post; mWeakWebView = new WeakReference(webView); mResourceVars = new ReaderResourceVars(webView.getContext()); + + // 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() { @@ -224,7 +228,7 @@ private String formatPostContentForWebView(String content) { // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds - if (canEnableJavaScript(mPost)) { + if (canEnableJavaScript()) { sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidthPx).append("px !important;") .append(" height: ").append(mResourceVars.videoHeightPx).append("px !important; }"); } else { @@ -311,8 +315,8 @@ private ImageSize getImageSizeFromQueryParams(final String imageUrl) { /* * javascript should only be enabled for wp blogs (not external feeds) */ - static boolean canEnableJavaScript(ReaderPost post) { - return post != null && post.isWP(); + private boolean canEnableJavaScript() { + return mPost != null && mPost.isWP(); } /* From 8ebe947992aae7bacf00c096079bf40ac164dcf2 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Sun, 31 Aug 2014 22:38:37 -0400 Subject: [PATCH 36/61] Renamed video resource vars to clarify that they're DP rather than PX --- .../wordpress/android/ui/reader/ReaderPostRenderer.java | 4 ++-- .../wordpress/android/ui/reader/ReaderResourceVars.java | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) 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 index 9908a24ae533..a7f788b0da59 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -229,8 +229,8 @@ private String formatPostContentForWebView(String content) { // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds if (canEnableJavaScript()) { - sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidthPx).append("px !important;") - .append(" height: ").append(mResourceVars.videoHeightPx).append("px !important; }"); + sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidthDp).append("px !important;") + .append(" height: ").append(mResourceVars.videoHeightDp).append("px !important; }"); } else { sbHtml.append(" iframe, embed { display: none; }"); } 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 index fcc5e7ebda65..928c81fae1f8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -24,8 +24,8 @@ class ReaderResourceVars { final int fullSizeImageWidthPx; final int featuredImageHeightPx; - final int videoWidthPx; - final int videoHeightPx; + final int videoWidthDp; + final int videoHeightDp; final int colorGreyExtraLight; final int mediumAnimTime; @@ -64,7 +64,8 @@ class ReaderResourceVars { } fullSizeImageWidthPx = imageWidth; - videoWidthPx = DisplayUtils.pxToDp(context, fullSizeImageWidthPx - (marginLargePx * 2)); - videoHeightPx = (int) (videoWidthPx * 0.5625f); + // 16:9 ratio (YouTube standard) + videoWidthDp = DisplayUtils.pxToDp(context, fullSizeImageWidthPx - (marginLargePx * 2)); + videoHeightDp = (int) (videoWidthDp * 0.5625f); } } From 17847911e7e5a686f7be297984e90acd6b1076dd Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 09:21:27 -0400 Subject: [PATCH 37/61] Changed to use dp image sizes based on http://developer.android.com/guide/webapps/targeting.html --- .../android/ui/reader/ReaderPostRenderer.java | 38 +++++++++++++++---- .../android/ui/reader/ReaderResourceVars.java | 12 +++--- 2 files changed, 38 insertions(+), 12 deletions(-) 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 index a7f788b0da59..19c0157128eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -1,5 +1,6 @@ package org.wordpress.android.ui.reader; +import android.annotation.SuppressLint; import android.net.Uri; import android.os.Handler; import android.text.TextUtils; @@ -10,6 +11,7 @@ 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; @@ -23,6 +25,10 @@ * 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 { @@ -34,6 +40,7 @@ class ReaderPostRenderer { private String mRenderedHtml; private ImageSizeMap mAttachmentSizes; + @SuppressLint("SetJavaScriptEnabled") ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { if (webView == null) { throw new IllegalArgumentException("ReaderPostRenderer requires a webView"); @@ -127,9 +134,14 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { } String newImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, newWidth, newHeight, mPost.isPrivate); - String newImageTag = - String.format("", - newImageUrl, newWidth, newHeight); + String newImageTag; + if (newHeight > 0) { + newImageTag = String.format("", + newImageUrl, pxToDp(newWidth), pxToDp(newHeight)); + } else { + newImageTag = String.format("", + newImageUrl, pxToDp(newWidth)); + } int start = mRenderBuilder.indexOf(imageTag); if (start == -1) { @@ -229,14 +241,14 @@ private String formatPostContentForWebView(String content) { // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds if (canEnableJavaScript()) { - sbHtml.append(" iframe, embed { width: ").append(mResourceVars.videoWidthDp).append("px !important;") - .append(" height: ").append(mResourceVars.videoHeightDp).append("px !important; }"); + sbHtml.append(" iframe, embed { width: ").append(pxToDp(mResourceVars.videoWidthPx)).append("px !important;") + .append(" height: ").append(pxToDp(mResourceVars.videoHeightPx)).append("px !important; }"); } else { sbHtml.append(" iframe, embed { display: none; }"); } // don't allow any image to be wider than the viewport - sbHtml.append(" img { max-width: 100% !important; height: auto; }"); + sbHtml.append(" img { max-width: 100% !important; }"); // light grey background for large images so something appears while they're loading, with a // small bottom margin @@ -312,11 +324,23 @@ private ImageSize getImageSizeFromQueryParams(final String imageUrl) { return null; } + private int pxToDp(int px) { + if (px == 0) { + return 0; + } + ReaderWebView webView = mWeakWebView.get(); + if (webView == null || webView.getContext() == null) { + AppLog.w(AppLog.T.READER, "reader renderer > no context"); + return 0; + } + return DisplayUtils.pxToDp(webView.getContext(), px); + } + /* * javascript should only be enabled for wp blogs (not external feeds) */ private boolean canEnableJavaScript() { - return mPost != null && mPost.isWP(); + return mPost.isWP(); } /* 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 index 928c81fae1f8..17d8069ebcc2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -24,8 +24,8 @@ class ReaderResourceVars { final int fullSizeImageWidthPx; final int featuredImageHeightPx; - final int videoWidthDp; - final int videoHeightDp; + final int videoWidthPx; + final int videoHeightPx; final int colorGreyExtraLight; final int mediumAnimTime; @@ -54,7 +54,9 @@ class ReaderResourceVars { greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light); greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light); - int imageWidth = displayWidthPx - (listMarginWidthPx * 2); + // 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()); @@ -65,7 +67,7 @@ class ReaderResourceVars { fullSizeImageWidthPx = imageWidth; // 16:9 ratio (YouTube standard) - videoWidthDp = DisplayUtils.pxToDp(context, fullSizeImageWidthPx - (marginLargePx * 2)); - videoHeightDp = (int) (videoWidthDp * 0.5625f); + videoWidthPx = fullSizeImageWidthPx - (marginLargePx * 2); + videoHeightPx = (int) (videoWidthPx * 0.5625f); } } From d8a57186a49db310037653a2327dbd1be3930750 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 09:23:19 -0400 Subject: [PATCH 38/61] returned missing "height: auto" to IMG style --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 19c0157128eb..5f05540adf4b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -248,7 +248,7 @@ private String formatPostContentForWebView(String content) { } // don't allow any image to be wider than the viewport - sbHtml.append(" img { max-width: 100% !important; }"); + sbHtml.append(" img { max-width: 100%; height: auto; }"); // light grey background for large images so something appears while they're loading, with a // small bottom margin From 249f943def3ccd5601c28fb89bc09db3ac9a0191 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 09:49:27 -0400 Subject: [PATCH 39/61] Small images are no longer resized to full width --- .../android/ui/reader/ReaderPostRenderer.java | 22 +++++++++++++++--- .../ui/reader/utils/ReaderImageScanner.java | 23 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) 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 index 5f05540adf4b..92bd2387135c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -112,14 +112,19 @@ private void renderHtmlContent(final String htmlContent) { /* * called when image scanner finds an image, tries to replace the image tag with one that - * has height & width attributes set + * has height & width attributes set correctly for the current display */ private void replaceImageTag(final String imageTag, final String imageUrl) { - ImageSize origSize = getImageSize(imageUrl); + ImageSize origSize = getImageSize(imageTag, imageUrl); if (origSize == null) { return; } + // don't resize small images + if (origSize.width > 0 && origSize.width < (mResourceVars.fullSizeImageWidthPx / 4)) { + return; + } + int newWidth; int newHeight; if (origSize.width > 0 && origSize.height > 0) { @@ -284,12 +289,14 @@ private String formatPostContentForWebView(String content) { return sbHtml.toString(); } - private ImageSize getImageSize(final String imageUrl) { + private ImageSize getImageSize(final String imageTag, final String imageUrl) { ImageSize size = getImageSizeFromAttachments(imageUrl); if (size != null) { return size; } else if (imageUrl.contains("?")) { return getImageSizeFromQueryParams(imageUrl); + } else if (imageTag.contains("width=")) { + return getImageSizeFromAttributes(imageTag); } else { return null; } @@ -324,6 +331,15 @@ private ImageSize getImageSizeFromQueryParams(final String imageUrl) { return null; } + private ImageSize getImageSizeFromAttributes(final String imageTag) { + int width = ReaderImageScanner.getWidthAttrValue(imageTag); + if (width == 0) { + return null; + } + int height = ReaderImageScanner.getHeightAttrValue(imageTag); + return new ImageSize(width, height); + } + private int pxToDp(int px) { if (px == 0) { return 0; 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 ca289747222e..5b5bf0b8642b 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 @@ -32,6 +32,11 @@ public static interface ImageScanListener { "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*(?:'|\")(.*?)(?:'|\")", @@ -117,7 +122,7 @@ public String getBestFeaturedImage() { /* * returns the integer value from the width attribute in the passed html tag */ - private int getWidthAttrValue(final String tag) { + public static int getWidthAttrValue(final String tag) { if (tag == null) { return 0; } @@ -131,10 +136,22 @@ private int getWidthAttrValue(final String tag) { } } + public static int getHeightAttrValue(final String tag) { + if (tag == null) { + return 0; + } + Matcher matcher = HEIGHT_ATTR_PATTERN.matcher(tag); + if (matcher.find()) { + return StringUtils.stringToInt(tag.substring(matcher.start() + 8, matcher.end() - 1), 0); + } else { + return 0; + } + } + /* * returns the value from the src attribute in the passed html tag */ - private String getSrcAttrValue(final String tag) { + public static String getSrcAttrValue(final String tag) { if (tag == null) { return null; } @@ -153,7 +170,7 @@ private String getSrcAttrValue(final String tag) { * if the url is invalid, or the param doesn't exist, or the param value could not be * converted to an int */ - private int getIntQueryParam(final String url, final String param) { + private static int getIntQueryParam(final String url, final String param) { if (url == null || param == null || !url.startsWith("http") From 31dc6650c6cfc6689bf16eee3e353eeb460d708b Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 10:09:34 -0400 Subject: [PATCH 40/61] Added handling of images higher than they are wide --- .../android/ui/reader/ReaderPostRenderer.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) 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 index 92bd2387135c..7040c21bd076 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -128,9 +128,15 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { int newWidth; int newHeight; if (origSize.width > 0 && origSize.height > 0) { - float ratio = ((float) origSize.height / (float) origSize.width); - newWidth = mResourceVars.fullSizeImageWidthPx; - newHeight = (int) (newWidth * ratio); + if (origSize.height > origSize.width) { + newHeight = mResourceVars.fullSizeImageWidthPx; + float ratio = ((float) origSize.width / (float) origSize.height); + newWidth = (int) (newHeight * ratio); + } else { + float ratio = ((float) origSize.height / (float) origSize.width); + newWidth = mResourceVars.fullSizeImageWidthPx; + newHeight = (int) (newWidth * ratio); + } } else if (origSize.width > 0) { newWidth = mResourceVars.fullSizeImageWidthPx; newHeight = 0; From dee83898096b26dbc68855e230ec62614bba5a61 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 10:18:54 -0400 Subject: [PATCH 41/61] Corrected centering of portrait images --- .../android/ui/reader/ReaderPostRenderer.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) 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 index 7040c21bd076..6c04ff2487e5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -261,15 +261,11 @@ private String formatPostContentForWebView(String content) { // don't allow any image to be wider than the viewport sbHtml.append(" img { max-width: 100%; height: auto; }"); - // light grey background for large images so something appears while they're loading, with a - // small bottom margin - sbHtml.append(" img.size-full, img.size-large { display: block;") - .append(" background-color ").append(mResourceVars.greyExtraLightStr).append(";") + // center large/medium images, and provide a small bottom margin + sbHtml.append(" img.size-full, img.size-large, img.size-medium {") + .append(" display: block; margin-left: auto; margin-right: auto;") .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }"); - // center medium-sized wp image - sbHtml.append(" img.size-medium { display: block; margin-left: auto !important; margin-right: auto !important; }"); - // tiled image galleries look bad on mobile due to their hard-coded DIV and IMG sizes, so if // content contains a tiled image gallery, remove the height params and replace the width // params with ones that make images fit the width of the listView item, then adjust the From eebddfd9b6bb74a9af29ad9466d7ef977e67f7d3 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 11:03:52 -0400 Subject: [PATCH 42/61] CSS to enforce max image size now only applies to IMG tags without a WIDTH attribute --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 index 6c04ff2487e5..7d14c004cf12 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -258,8 +258,10 @@ private String formatPostContentForWebView(String content) { sbHtml.append(" iframe, embed { display: none; }"); } - // don't allow any image to be wider than the viewport - sbHtml.append(" img { max-width: 100%; height: auto; }"); + // make sure images without a width aren't wider than the max + sbHtml.append(" img:not([width]) {") + .append(" max-width: ").append(pxToDp(mResourceVars.fullSizeImageWidthPx)).append("px;") + .append(" height: auto; }"); // center large/medium images, and provide a small bottom margin sbHtml.append(" img.size-full, img.size-large, img.size-medium {") From 549ebaccf0322d419bd73e984d5ea11824f33342 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 11:35:39 -0400 Subject: [PATCH 43/61] Reverted max width --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) 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 index 7d14c004cf12..28b0025fae76 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -258,10 +258,8 @@ private String formatPostContentForWebView(String content) { sbHtml.append(" iframe, embed { display: none; }"); } - // make sure images without a width aren't wider than the max - sbHtml.append(" img:not([width]) {") - .append(" max-width: ").append(pxToDp(mResourceVars.fullSizeImageWidthPx)).append("px;") - .append(" height: auto; }"); + // make sure images aren't wider than the display + sbHtml.append(" img { max-width: 100%; }"); // center large/medium images, and provide a small bottom margin sbHtml.append(" img.size-full, img.size-large, img.size-medium {") From 6a8d56d7a5deb01d2a016e70f6cfd99ae39bd2ee Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 15:10:06 -0400 Subject: [PATCH 44/61] All images in content are now replaced. If size couldn't be discovered, image is replaced with one that uses 'size-none' class so we can enforce max width. --- .../android/ui/reader/ReaderPostRenderer.java | 93 ++++++++++--------- 1 file changed, 51 insertions(+), 42 deletions(-) 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 index 28b0025fae76..f3c8eea55443 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -34,6 +34,7 @@ class ReaderPostRenderer { private final ReaderResourceVars mResourceVars; private final ReaderPost mPost; + private final int mMinFullSizeWidthDp; private final WeakReference mWeakWebView; private StringBuilder mRenderBuilder; @@ -52,6 +53,7 @@ class ReaderPostRenderer { mPost = post; mWeakWebView = new WeakReference(webView); mResourceVars = new ReaderResourceVars(webView.getContext()); + mMinFullSizeWidthDp = pxToDp(mResourceVars.fullSizeImageWidthPx / 4); // enable JavaScript in the webView if it's safe to do so, otherwise videos // and other embedded content won't work @@ -112,54 +114,62 @@ private void renderHtmlContent(final String htmlContent) { /* * 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 + * 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); - if (origSize == null) { - return; + boolean hasWidth = (origSize != null && origSize.width > 0); + boolean isFullSize = hasWidth && (origSize.width >= mMinFullSizeWidthDp); + + final String newImageTag; + if (isFullSize) { + newImageTag = makeFullSizeImageTag(imageUrl, origSize.width, origSize.height); + } else if (hasWidth) { + newImageTag = makeImageTag(imageUrl, origSize.width, origSize.height, "size-none"); + } else { + newImageTag = String.format("", imageUrl); } - // don't resize small images - if (origSize.width > 0 && origSize.width < (mResourceVars.fullSizeImageWidthPx / 4)) { + 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 className) { + String newImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, width, height, mPost.isPrivate); + if (height > 0) { + return String.format("", + className, newImageUrl, pxToDp(width), pxToDp(height)); + } else { + return String.format("", + className, newImageUrl, pxToDp(width)); + } + } + + private String makeFullSizeImageTag(final String imageUrl, int width, int height) { int newWidth; int newHeight; - if (origSize.width > 0 && origSize.height > 0) { - if (origSize.height > origSize.width) { + if (width > 0 && height > 0) { + if (height > width) { newHeight = mResourceVars.fullSizeImageWidthPx; - float ratio = ((float) origSize.width / (float) origSize.height); + float ratio = ((float) width / (float) height); newWidth = (int) (newHeight * ratio); } else { - float ratio = ((float) origSize.height / (float) origSize.width); + float ratio = ((float) height / (float) width); newWidth = mResourceVars.fullSizeImageWidthPx; newHeight = (int) (newWidth * ratio); } - } else if (origSize.width > 0) { + } else { newWidth = mResourceVars.fullSizeImageWidthPx; newHeight = 0; - } else { - return; } - String newImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, newWidth, newHeight, mPost.isPrivate); - String newImageTag; - if (newHeight > 0) { - newImageTag = String.format("", - newImageUrl, pxToDp(newWidth), pxToDp(newHeight)); - } else { - newImageTag = String.format("", - newImageUrl, pxToDp(newWidth)); - } - - 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); + return makeImageTag(imageUrl, newWidth, newHeight, "size-full"); } /* @@ -212,8 +222,8 @@ private String getFeaturedImageHtml() { private String formatPostContentForWebView(String content) { StringBuilder sbHtml = new StringBuilder(""); - // title isn't strictly necessary, but source is invalid html5 without one - sbHtml.append("Reader Post"); + // title isn't necessary, but it's invalid html5 without one and it helps while debugging + sbHtml.append(String.format("%s", mPost.getTitle())); // https://developers.google.com/chrome/mobile/docs/webview/pixelperfect sbHtml.append(""); @@ -258,12 +268,14 @@ private String formatPostContentForWebView(String content) { sbHtml.append(" iframe, embed { display: none; }"); } - // make sure images aren't wider than the display - sbHtml.append(" img { max-width: 100%; }"); + // make sure images without sizes aren't wider than the display + sbHtml.append(" img.size-none { max-width: 100% !important; height: auto; }"); - // center large/medium images, and provide a small bottom margin + // center large/medium images, provide a small bottom margin, and add a background color + // so the user sees something while image is loading sbHtml.append(" img.size-full, img.size-large, img.size-medium {") .append(" display: block; margin-left: auto; margin-right: auto;") + .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append(";") .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }"); // tiled image galleries look bad on mobile due to their hard-coded DIV and IMG sizes, so if @@ -323,9 +335,9 @@ private ImageSize getImageSizeFromQueryParams(final String imageUrl) { if (param != null) { String[] sizes = param.split(","); if (sizes.length == 2) { - int width = StringUtils.stringToInt(sizes[0]); - int height = StringUtils.stringToInt(sizes[1]); - return new ImageSize(width, height); + return new ImageSize( + StringUtils.stringToInt(sizes[0]), + StringUtils.stringToInt(sizes[1])); } } } @@ -334,12 +346,9 @@ private ImageSize getImageSizeFromQueryParams(final String imageUrl) { } private ImageSize getImageSizeFromAttributes(final String imageTag) { - int width = ReaderImageScanner.getWidthAttrValue(imageTag); - if (width == 0) { - return null; - } - int height = ReaderImageScanner.getHeightAttrValue(imageTag); - return new ImageSize(width, height); + return new ImageSize( + ReaderImageScanner.getWidthAttrValue(imageTag), + ReaderImageScanner.getHeightAttrValue(imageTag)); } private int pxToDp(int px) { From 978cd413d91db46a82b0cda279c2a5edd7e77066 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 15:34:28 -0400 Subject: [PATCH 45/61] Fixes and simplifications for tiled galleries --- .../android/ui/reader/ReaderPostRenderer.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) 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 index f3c8eea55443..826650e0dd85 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -219,7 +219,7 @@ private String getFeaturedImageHtml() { /* * returns the full content, including CSS, that will be shown in the WebView for this post */ - private String formatPostContentForWebView(String content) { + private String formatPostContentForWebView(final String content) { StringBuilder sbHtml = new StringBuilder(""); // title isn't necessary, but it's invalid html5 without one and it helps while debugging @@ -269,7 +269,7 @@ private String formatPostContentForWebView(String content) { } // make sure images without sizes aren't wider than the display - sbHtml.append(" img.size-none { max-width: 100% !important; height: auto; }"); + sbHtml.append(" img.size-none { max-width: 100% !important; height: auto !important; }"); // center large/medium images, provide a small bottom margin, and add a background color // so the user sees something while image is loading @@ -278,19 +278,10 @@ private String formatPostContentForWebView(String content) { .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append(";") .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }"); - // tiled image galleries look bad on mobile due to their hard-coded DIV and IMG sizes, so if - // content contains a tiled image gallery, remove the height params and replace the width - // params with ones that make images fit the width of the listView item, then adjust the - // relevant CSS classes so their height/width are auto, and add top/bottom margin to images + // set tiled gallery containers to auto height/width if (content.contains("tiled-gallery-item")) { - String widthParam = "w=" + Integer.toString(mResourceVars.fullSizeImageWidthPx); - content = content.replaceAll("w=[0-9]+", widthParam).replaceAll("h=[0-9]+", ""); + AppLog.d(AppLog.T.READER, "reader renderer > tiled gallery"); sbHtml.append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") - .append(" div.tiled-gallery-item img { ") - .append(" width: auto !important; height: auto !important;") - .append(" margin-top: ").append(mResourceVars.marginExtraSmallPx).append("px; ") - .append(" margin-bottom: ").append(mResourceVars.marginExtraSmallPx).append("px; ") - .append(" }") .append(" div.tiled-gallery-caption { clear: both; }"); } From 361a368647aff9e03381ee7bf29ab0f3dfad47df Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 16:09:53 -0400 Subject: [PATCH 46/61] Cleanup --- .../android/ui/reader/ReaderPostRenderer.java | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) 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 index 826650e0dd85..adfaffdc4aa2 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -223,41 +223,41 @@ private String formatPostContentForWebView(final String content) { StringBuilder sbHtml = new StringBuilder(""); // title isn't necessary, but it's invalid html5 without one and it helps while debugging - sbHtml.append(String.format("%s", mPost.getTitle())); + sbHtml.append(String.format("%s", mPost.getTitle())) // https://developers.google.com/chrome/mobile/docs/webview/pixelperfect - sbHtml.append(""); + .append("") // use "Open Sans" Google font - sbHtml.append(""); + .append("") - sbHtml.append(""); - - sbHtml.append("") + sbHtml.append("") + .append("") .append(content) .append(""); From daa585b40b2e3fe35c2ab73df70a565938bebbed Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 16:22:13 -0400 Subject: [PATCH 47/61] Added detection of mid-size images --- .../android/ui/reader/ReaderPostRenderer.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 index adfaffdc4aa2..b09f2981e7fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -35,6 +35,7 @@ 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; @@ -53,7 +54,9 @@ class ReaderPostRenderer { mPost = post; mWeakWebView = new WeakReference(webView); mResourceVars = new ReaderResourceVars(webView.getContext()); - mMinFullSizeWidthDp = pxToDp(mResourceVars.fullSizeImageWidthPx / 4); + + 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 @@ -121,10 +124,15 @@ 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 { @@ -272,7 +280,7 @@ private String formatPostContentForWebView(final String content) { sbHtml.append(" img.size-none { max-width: 100% !important; height: auto !important; }") // center large/medium images, provide a small bottom margin, and add a background color - // so the user sees something while images are loading + // so the user sees something while they're loading .append(" img.size-full, img.size-large, img.size-medium {") .append(" display: block; margin-left: auto; margin-right: auto;") .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append(";") From 3d8a79d562bf38c1adf9012127031914eeff50b2 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 16:34:46 -0400 Subject: [PATCH 48/61] Switched to using WordPress.getContext() in pxToDp --- .../wordpress/android/ui/reader/ReaderPostRenderer.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 index b09f2981e7fe..78a297ffc358 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -7,6 +7,7 @@ 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; @@ -353,12 +354,7 @@ private int pxToDp(int px) { if (px == 0) { return 0; } - ReaderWebView webView = mWeakWebView.get(); - if (webView == null || webView.getContext() == null) { - AppLog.w(AppLog.T.READER, "reader renderer > no context"); - return 0; - } - return DisplayUtils.pxToDp(webView.getContext(), px); + return DisplayUtils.pxToDp(WordPress.getContext(), px); } /* From ae8abeee86de2adeff928f7c361aed21cad7ddd4 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 19:15:31 -0400 Subject: [PATCH 49/61] Fixed regex bug that caused image tags to be skipped if not closed by /> --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 3 +++ .../wordpress/android/ui/reader/utils/ReaderImageScanner.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) 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 index 78a297ffc358..402d87b337a8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -249,6 +249,9 @@ private String formatPostContentForWebView(final String content) { // make sure long strings don't force the user to scroll horizontally .append(" body, p, div, a { word-wrap: break-word; }") + // counteract pre-defined height/width styles + .append(" p, div, dl, table { width: auto !important; height: auto !important; }") + // use a consistent top/bottom margin for paragraphs, with no top margin for the first one .append(" p { margin-top: ").append(mResourceVars.marginSmallPx).append("px;") .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }") 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 5b5bf0b8642b..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 @@ -24,7 +24,7 @@ public static interface ImageScanListener { // 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 @@ -151,7 +151,7 @@ public static int getHeightAttrValue(final String tag) { /* * returns the value from the src attribute in the passed html tag */ - public static String getSrcAttrValue(final String tag) { + private static String getSrcAttrValue(final String tag) { if (tag == null) { return null; } From 711c5e4dd7ef3953f197dfd922eaad1d2c1e9812 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 20:58:01 -0400 Subject: [PATCH 50/61] Replaced String.format() calls in ReaderPostRenderer after profiling showed them to be a bottleneck --- .../android/ui/reader/ReaderPostRenderer.java | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) 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 index 402d87b337a8..8123318e886d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -43,8 +43,17 @@ class ReaderPostRenderer { private String mRenderedHtml; private ImageSizeMap mAttachmentSizes; + private static int mDebugCnt = 0; + @SuppressLint("SetJavaScriptEnabled") ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { + /*mDebugCnt++; + if (mDebugCnt == 1) { + Debug.startMethodTracing("wordpress"); + } else if (mDebugCnt == 5) { + Debug.stopMethodTracing(); + }*/ + if (webView == null) { throw new IllegalArgumentException("ReaderPostRenderer requires a webView"); } @@ -137,7 +146,7 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { } else if (hasWidth) { newImageTag = makeImageTag(imageUrl, origSize.width, origSize.height, "size-none"); } else { - newImageTag = String.format("", imageUrl); + newImageTag = ""; } int start = mRenderBuilder.indexOf(imageTag); @@ -149,14 +158,19 @@ private void replaceImageTag(final String imageTag, final String imageUrl) { mRenderBuilder.replace(start, start + imageTag.length(), newImageTag); } - private String makeImageTag(final String imageUrl, int width, int height, final String className) { + 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 String.format("", - className, newImageUrl, pxToDp(width), pxToDp(height)); + return new StringBuilder("") + .toString(); } else { - return String.format("", - className, newImageUrl, pxToDp(width)); + return new StringBuilder("") + .toString(); } } @@ -222,7 +236,7 @@ private String getFeaturedImageHtml() { mResourceVars.featuredImageHeightPx, mPost.isPrivate); - return String.format("", imageUrl); + return ""; } /* @@ -231,8 +245,8 @@ private String getFeaturedImageHtml() { private String formatPostContentForWebView(final String content) { StringBuilder sbHtml = new StringBuilder(""); - // title isn't necessary, but it's invalid html5 without one and it helps while debugging - sbHtml.append(String.format("%s", mPost.getTitle())) + // 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("") @@ -246,12 +260,12 @@ private String formatPostContentForWebView(final String content) { .append(" p, div { line-height: 1.6em; font-size: 1em; }") .append(" h1, h2 { line-height: 1.2em; }") - // make sure long strings don't force the user to scroll horizontally - .append(" body, p, div, a { word-wrap: break-word; }") - // counteract pre-defined height/width styles .append(" p, div, dl, table { width: auto !important; height: auto !important; }") + // make sure long strings don't force the user to scroll horizontally + .append(" body, p, div, a { word-wrap: break-word; }") + // use a consistent top/bottom margin for paragraphs, with no top margin for the first one .append(" p { margin-top: ").append(mResourceVars.marginSmallPx).append("px;") .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }") @@ -307,15 +321,13 @@ private String formatPostContentForWebView(final String content) { private ImageSize getImageSize(final String imageTag, final String imageUrl) { ImageSize size = getImageSizeFromAttachments(imageUrl); - if (size != null) { - return size; - } else if (imageUrl.contains("?")) { - return getImageSizeFromQueryParams(imageUrl); - } else if (imageTag.contains("width=")) { - return getImageSizeFromAttributes(imageTag); - } else { - return null; + 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) { From dabe4079d6be79fbfa011bf939da8aa20e4b3ae2 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 1 Sep 2014 21:25:07 -0400 Subject: [PATCH 51/61] Removed debug code --- .../wordpress/android/ui/reader/ReaderPostRenderer.java | 9 --------- 1 file changed, 9 deletions(-) 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 index 8123318e886d..361a345b2149 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -43,17 +43,8 @@ class ReaderPostRenderer { private String mRenderedHtml; private ImageSizeMap mAttachmentSizes; - private static int mDebugCnt = 0; - @SuppressLint("SetJavaScriptEnabled") ReaderPostRenderer(ReaderWebView webView, ReaderPost post) { - /*mDebugCnt++; - if (mDebugCnt == 1) { - Debug.startMethodTracing("wordpress"); - } else if (mDebugCnt == 5) { - Debug.stopMethodTracing(); - }*/ - if (webView == null) { throw new IllegalArgumentException("ReaderPostRenderer requires a webView"); } From f959af924b204ff6f625f5c47d3390b6369f878e Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 2 Sep 2014 09:03:44 -0400 Subject: [PATCH 52/61] Added max-width:100% for all images --- .../android/ui/reader/ReaderPostRenderer.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) 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 index 361a345b2149..ca5b6e525fea 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -274,32 +274,30 @@ private String formatPostContentForWebView(final String content) { .append(" border-left: 3px solid ").append(mResourceVars.greyLightStr).append("; }") // show links in the same color they are elsewhere in the app - .append(" a { text-decoration: none; color: ").append(mResourceVars.linkColorStr).append("; }"); + .append(" a { text-decoration: none; color: ").append(mResourceVars.linkColorStr).append("; }") - // if javascript is allowed, make sure embedded videos fit the browser width and - // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds - if (canEnableJavaScript()) { - sbHtml.append(" iframe, embed { width: ").append(pxToDp(mResourceVars.videoWidthPx)).append("px !important;") - .append(" height: ").append(pxToDp(mResourceVars.videoHeightPx)).append("px !important; }"); - } else { - sbHtml.append(" iframe, embed { display: none; }"); - } - - // make sure images without sizes aren't wider than the display - sbHtml.append(" img.size-none { max-width: 100% !important; height: auto !important; }") + // make sure images aren't wider than the display, strictly enforced for images without size + .append(" img { max-width: 100%; }") + .append(" img.size-none { max-width: 100% !important; height: auto !important; }") // center large/medium images, provide a small bottom margin, and add a background color // so the user sees something while they're loading .append(" img.size-full, img.size-large, img.size-medium {") .append(" display: block; margin-left: auto; margin-right: auto;") .append(" background-color: ").append(mResourceVars.greyExtraLightStr).append(";") - .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }"); + .append(" margin-bottom: ").append(mResourceVars.marginSmallPx).append("px; }") // set tiled gallery containers to auto height/width - if (content.contains("tiled-gallery-item")) { - AppLog.d(AppLog.T.READER, "reader renderer > tiled gallery"); - sbHtml.append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") - .append(" div.tiled-gallery-caption { clear: both; }"); + .append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") + .append(" div.tiled-gallery-caption { clear: both; }"); + + // if javascript is allowed, make sure embedded videos fit the browser width and + // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds + if (canEnableJavaScript()) { + sbHtml.append(" iframe, embed { width: ").append(pxToDp(mResourceVars.videoWidthPx)).append("px !important;") + .append(" height: ").append(pxToDp(mResourceVars.videoHeightPx)).append("px !important; }"); + } else { + sbHtml.append(" iframe, embed { display: none; }"); } sbHtml.append("") From b40578b2bbbb291b2d64e6545e7065e35a99f806 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 2 Sep 2014 09:24:59 -0400 Subject: [PATCH 53/61] Removed unused context from previous merge --- .../wordpress/android/ui/reader/ReaderPostDetailFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 0dc777697a0e..c8252e2d58c8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -238,7 +238,6 @@ public void onAttach(Activity activity) { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.reader_fragment_post_detail, container, false); - final Context context = container.getContext(); // locate & init listView mListView = (WPListView) view.findViewById(android.R.id.list); From 5a10744bd3a99da5170750ff27eceb40fa3847b0 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 2 Sep 2014 10:11:37 -0400 Subject: [PATCH 54/61] Removed hyperlink color from blog name in detail header, added divider --- .../android/ui/reader/ReaderPostDetailFragment.java | 6 +++++- .../main/res/layout/reader_listitem_post_detail.xml | 12 +++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index c8252e2d58c8..b7f12f1ad912 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1026,7 +1026,9 @@ private class ShowPostTask extends AsyncTask { ImageView imgBtnComment; ImageView imgDropDown; WPNetworkImageView imgAvatar; + ViewGroup layoutDetailHeader; + View dividerHeader; @Override protected void onPreExecute() { @@ -1063,6 +1065,7 @@ protected Boolean doInBackground(Void... params) { imgBtnComment = (ImageView) mLayoutIcons.findViewById(R.id.image_comment_btn); layoutDetailHeader = (ViewGroup) container.findViewById(R.id.layout_detail_header); + dividerHeader = container.findViewById(R.id.divider_header); return true; } @@ -1126,9 +1129,10 @@ public void onClick(View view) { 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); + dividerHeader.setVisibility(View.GONE); } // enable reblogging wp posts 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..fcdf6b176c62 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" /> @@ -65,6 +65,16 @@ + + Date: Tue, 2 Sep 2014 10:28:16 -0400 Subject: [PATCH 55/61] Removed hyperlink color from blog name in detail header, added divider --- .../android/ui/reader/ReaderPostDetailFragment.java | 4 ---- .../android/ui/reader/ReaderPostRenderer.java | 5 ++++- .../android/ui/reader/ReaderResourceVars.java | 2 ++ .../main/res/layout/reader_listitem_post_detail.xml | 10 ---------- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index b7f12f1ad912..14a93c7fad72 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1026,9 +1026,7 @@ private class ShowPostTask extends AsyncTask { ImageView imgBtnComment; ImageView imgDropDown; WPNetworkImageView imgAvatar; - ViewGroup layoutDetailHeader; - View dividerHeader; @Override protected void onPreExecute() { @@ -1065,7 +1063,6 @@ protected Boolean doInBackground(Void... params) { imgBtnComment = (ImageView) mLayoutIcons.findViewById(R.id.image_comment_btn); layoutDetailHeader = (ViewGroup) container.findViewById(R.id.layout_detail_header); - dividerHeader = container.findViewById(R.id.divider_header); return true; } @@ -1132,7 +1129,6 @@ public void onClick(View view) { // hide header if this fragment was shown from blog preview if (isBlogPreview()) { layoutDetailHeader.setVisibility(View.GONE); - dividerHeader.setVisibility(View.GONE); } // enable reblogging wp posts 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 index ca5b6e525fea..a6db0a54cb90 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -289,7 +289,10 @@ private String formatPostContentForWebView(final String content) { // set tiled gallery containers to auto height/width .append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") - .append(" div.tiled-gallery-caption { clear: both; }"); + .append(" div.tiled-gallery-caption { clear: both; }") + + // see http://codex.wordpress.org/CSS + .append(" .wp-caption { font-size: smaller; color: ").append(mResourceVars.greyMediumStr).append("; }"); // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds 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 index 17d8069ebcc2..fba86d3e9ad0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -31,6 +31,7 @@ class ReaderResourceVars { final int mediumAnimTime; final String linkColorStr; + final String greyMediumStr; final String greyLightStr; final String greyExtraLightStr; @@ -51,6 +52,7 @@ class ReaderResourceVars { mediumAnimTime = resources.getInteger(android.R.integer.config_mediumAnimTime); linkColorStr = HtmlUtils.colorResToHtmlColor(context, R.color.reader_hyperlink); + greyMediumStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_medium); greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light); greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light); 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 fcdf6b176c62..e346246e84d9 100644 --- a/WordPress/src/main/res/layout/reader_listitem_post_detail.xml +++ b/WordPress/src/main/res/layout/reader_listitem_post_detail.xml @@ -65,16 +65,6 @@ - - Date: Tue, 2 Sep 2014 11:01:39 -0400 Subject: [PATCH 56/61] Improved .wp_caption styling --- .../wordpress/android/ui/reader/ReaderPostRenderer.java | 9 +++++++-- .../wordpress/android/ui/reader/ReaderResourceVars.java | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) 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 index a6db0a54cb90..fbb36be6b950 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -291,8 +291,13 @@ private String formatPostContentForWebView(final String content) { .append(" div.gallery-row, div.gallery-group { width: auto !important; height: auto !important; }") .append(" div.tiled-gallery-caption { clear: both; }") - // see http://codex.wordpress.org/CSS - .append(" .wp-caption { font-size: smaller; color: ").append(mResourceVars.greyMediumStr).append("; }"); + // see http://codex.wordpress.org/CSS#WordPress_Generated_Classes + .append(" .wp-caption { background-color: ").append(mResourceVars.greyExtraLightStr).append("; }") + .append(" .wp-caption img { margin: 0px; }") + .append(" .wp-caption .wp-caption-text {") + .append(" font-size: smaller; line-height: 1.2em; margin: 0px;") + .append(" padding: ").append(mResourceVars.marginExtraSmallPx).append("px; ") + .append(" color: ").append(mResourceVars.greyMediumDarkStr).append("; }"); // if javascript is allowed, make sure embedded videos fit the browser width and // use 16:9 ratio (YouTube standard) - if not allowed, hide iframes/embeds 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 index fba86d3e9ad0..03ac68be85b4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java @@ -31,7 +31,7 @@ class ReaderResourceVars { final int mediumAnimTime; final String linkColorStr; - final String greyMediumStr; + final String greyMediumDarkStr; final String greyLightStr; final String greyExtraLightStr; @@ -52,7 +52,7 @@ class ReaderResourceVars { mediumAnimTime = resources.getInteger(android.R.integer.config_mediumAnimTime); linkColorStr = HtmlUtils.colorResToHtmlColor(context, R.color.reader_hyperlink); - greyMediumStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_medium); + 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); From d7927d19ed3b46c1d4d0bf2d07d31020a450af90 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 2 Sep 2014 11:56:19 -0400 Subject: [PATCH 57/61] Fixed lack of centering of portrait images with captions. --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index fbb36be6b950..940a6b2b2f05 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -293,7 +293,7 @@ private String formatPostContentForWebView(final String content) { // see http://codex.wordpress.org/CSS#WordPress_Generated_Classes .append(" .wp-caption { background-color: ").append(mResourceVars.greyExtraLightStr).append("; }") - .append(" .wp-caption img { margin: 0px; }") + .append(" .wp-caption img { margin-top: 0px; margin-bottom: 0px; }") .append(" .wp-caption .wp-caption-text {") .append(" font-size: smaller; line-height: 1.2em; margin: 0px;") .append(" padding: ").append(mResourceVars.marginExtraSmallPx).append("px; ") From 614fd4568b91e3cdb6223d835ed9dd696df27cbd Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 2 Sep 2014 20:03:12 -0400 Subject: [PATCH 58/61] Added null check when getting attachments, fixed bug that caused mime-type to be read from the parent JSON instead of the attachment JSON --- .../org/wordpress/android/ui/reader/ReaderPostRenderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 940a6b2b2f05..f7c41302226e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java @@ -395,8 +395,7 @@ class ImageSizeMap extends HashMap { while (it.hasNext()) { JSONObject jsonAttach = json.optJSONObject(it.next()); - String mimeType = JSONUtil.getString(json, "mime_type"); - if (mimeType.startsWith("image")) { + 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"); From 572bcc24d242bbc90980c48281e3312b97ad25c8 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 3 Sep 2014 08:27:57 -0400 Subject: [PATCH 59/61] Fix #1806 - viewing a single post in the pager now handles the case when the post doesn't already exist in the local database. --- .../ui/reader/ReaderPostDetailFragment.java | 1 + .../ui/reader/ReaderPostPagerActivity.java | 21 ++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java index 14a93c7fad72..0d77842d9dc4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostDetailFragment.java @@ -1080,6 +1080,7 @@ 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; 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); From 20c49b76ca015fbdf2474782fb6ca2bac84f0b4c Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 3 Sep 2014 11:26:46 -0400 Subject: [PATCH 60/61] Replaced String.format() with string concatenation in ReaderUtils and PhotonUtils after profiler showed String.format() to be hurting performance --- .../wordpress/android/ui/reader/utils/ReaderUtils.java | 6 +++--- .../java/org/wordpress/android/util/PhotonUtils.java | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java index c207641f6853..63c64ce5399a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderUtils.java @@ -150,11 +150,11 @@ private static String getPrivateImageForDisplay(final String imageUrl, int width final String query; if (width > 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/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 = ""; } From db54ca07c7847b5860b1d841c825025cbd25516a Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 3 Sep 2014 17:48:32 -0400 Subject: [PATCH 61/61] Fix #1809 - post list now refreshes correctly after reader db is upgraded, and after login/signout --- .../android/ui/reader/ReaderPostListActivity.java | 7 ++++++- .../android/ui/reader/ReaderPostListFragment.java | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) 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 */