From 7bb8176b3620f8c2213f78f55fb3f1c7caaec16b Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 26 Jun 2014 12:57:12 -0400 Subject: [PATCH 01/22] Added UndoBar to build.gradle - https://github.com/soarcn/UndoBar --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 6941ab0d7bfb..e762aa3cd466 100644 --- a/build.gradle +++ b/build.gradle @@ -71,6 +71,7 @@ android { compile 'com.github.castorflex.smoothprogressbar:library:0.4.0' compile 'com.github.chrisbanes.photoview:library:1.2.3' compile 'net.simonvt.menudrawer:menudrawer:3.0.6' + compile 'com.cocosw:undobar:1.+@aar' androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.+' androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0' From 7b1c214a828274228beb83db387b5d79bae102c3 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 26 Jun 2014 14:20:02 -0400 Subject: [PATCH 02/22] Added dropdown arrow drawable --- res/drawable-hdpi/reader_arrow_dropdown.png | Bin 0 -> 3779 bytes res/drawable-mdpi/reader_arrow_dropdown.png | Bin 0 -> 3577 bytes res/drawable-xhdpi/reader_arrow_dropdown.png | Bin 0 -> 3950 bytes res/drawable-xxhdpi/reader_arrow_dropdown.png | Bin 0 -> 4374 bytes res/layout/reader_listitem_post_excerpt.xml | 13 +++++++++++++ .../ui/reader/adapters/ReaderPostAdapter.java | 17 ++++++++++++++++- 6 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 res/drawable-hdpi/reader_arrow_dropdown.png create mode 100644 res/drawable-mdpi/reader_arrow_dropdown.png create mode 100644 res/drawable-xhdpi/reader_arrow_dropdown.png create mode 100644 res/drawable-xxhdpi/reader_arrow_dropdown.png diff --git a/res/drawable-hdpi/reader_arrow_dropdown.png b/res/drawable-hdpi/reader_arrow_dropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..e096cede2fe63bad001287c36f509dfba5e1ec23 GIT binary patch literal 3779 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 T?=Ryot_5ukJ@ra8yWjo=Sa8rg literal 0 HcmV?d00001 diff --git a/res/drawable-mdpi/reader_arrow_dropdown.png b/res/drawable-mdpi/reader_arrow_dropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..9dfe22251c44b586fbd06a0c3823ceeb01970eec GIT binary patch literal 3577 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 literal 0 HcmV?d00001 diff --git a/res/drawable-xhdpi/reader_arrow_dropdown.png b/res/drawable-xhdpi/reader_arrow_dropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..ab4083497b06bfec18a5db068a01a2b19c101c0c GIT binary patch literal 3950 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 literal 0 HcmV?d00001 diff --git a/res/layout/reader_listitem_post_excerpt.xml b/res/layout/reader_listitem_post_excerpt.xml index 7123e1925993..aaa3f0064cd2 100644 --- a/res/layout/reader_listitem_post_excerpt.xml +++ b/res/layout/reader_listitem_post_excerpt.xml @@ -44,6 +44,19 @@ android:layout_below="@+id/text_blog_name" android:layout_marginTop="@dimen/margin_small" android:layout_toRightOf="@+id/image_avatar" /> + + + = getCount()-1)) { mDataRequestedListener.onRequestData(); @@ -446,6 +459,7 @@ private static class PostViewHolder { private final ImageView imgBtnLike; private final ImageView imgBtnComment; private final ImageView imgBtnReblog; + private final ImageView imgDropDown; private final WPNetworkImageView imgFeatured; private final WPNetworkImageView imgAvatar; @@ -470,13 +484,14 @@ private static class PostViewHolder { imgBtnLike = (ImageView) view.findViewById(R.id.image_like_btn); imgBtnComment = (ImageView) view.findViewById(R.id.image_comment_btn); imgBtnReblog = (ImageView) view.findViewById(R.id.image_reblog_btn); + imgDropDown = (ImageView) view.findViewById(R.id.image_dropdown); layoutBottom = (ViewGroup) view.findViewById(R.id.layout_bottom); layoutPostHeader = (ViewGroup) view.findViewById(R.id.layout_post_header); // hide the post header (avatar, blog name & follow button) if we're showing posts // in a specific blog - if (postListType.equals(ReaderTypes.ReaderPostListType.BLOG_PREVIEW)) { + if (postListType == ReaderPostListType.BLOG_PREVIEW) { layoutPostHeader.setVisibility(View.GONE); } } From 3fa6f3366d35a186ba5b8515e55c774142c9ad2d Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 26 Jun 2014 21:04:03 -0400 Subject: [PATCH 03/22] Basic logic has been implemented w/o API call (since it doesn't exist yet) --- res/layout/reader_listitem_post_excerpt.xml | 5 +- res/values/strings.xml | 2 + .../android/datasets/ReaderPostTable.java | 5 ++ .../android/ui/reader/ReaderAnim.java | 8 +- .../ui/reader/ReaderPostListFragment.java | 82 +++++++++++++++++++ .../ui/reader/actions/ReaderBlogActions.java | 22 +++++ .../ui/reader/adapters/ReaderPostAdapter.java | 17 +++- 7 files changed, 132 insertions(+), 9 deletions(-) diff --git a/res/layout/reader_listitem_post_excerpt.xml b/res/layout/reader_listitem_post_excerpt.xml index aaa3f0064cd2..4b2f33349347 100644 --- a/res/layout/reader_listitem_post_excerpt.xml +++ b/res/layout/reader_listitem_post_excerpt.xml @@ -32,6 +32,7 @@ android:layout_marginRight="@dimen/margin_large" android:layout_marginTop="@dimen/margin_large" android:layout_toRightOf="@+id/image_avatar" + android:layout_toLeftOf="@+id/image_dropdown" android:ellipsize="end" android:maxLines="1" tools:text="text_blog_name" @@ -51,9 +52,9 @@ android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_alignParentRight="true" - android:padding="@dimen/margin_extra_small" + android:padding="@dimen/margin_medium" android:layout_marginLeft="@dimen/margin_medium" - android:layout_marginRight="@dimen/margin_large" + android:layout_marginRight="@dimen/margin_medium" android:background="@drawable/reader_transparent_selector" android:src="@drawable/reader_arrow_dropdown" /> diff --git a/res/values/strings.xml b/res/values/strings.xml index dfb92b7e1870..1f47f4e83738 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -595,6 +595,7 @@ Tags + Block this blog Share @@ -650,6 +651,7 @@ You already follow this blog Unable to follow this blog Unable to unfollow this blog + Posts from %s will no longer appear No posts with this tag diff --git a/src/org/wordpress/android/datasets/ReaderPostTable.java b/src/org/wordpress/android/datasets/ReaderPostTable.java index 75da0bebd089..12d299534300 100644 --- a/src/org/wordpress/android/datasets/ReaderPostTable.java +++ b/src/org/wordpress/android/datasets/ReaderPostTable.java @@ -296,6 +296,11 @@ public static int deletePostsWithTag(final ReaderTag tag) { return numDeleted; } + public static int deletePostsInBlog(long blogId) { + String[] args = {Long.toString(blogId)}; + return ReaderDatabase.getWritableDb().delete("tbl_posts", "blog_id = ?", args); + } + /* * returns the iso8601 published date of the oldest post with the passed tag */ diff --git a/src/org/wordpress/android/ui/reader/ReaderAnim.java b/src/org/wordpress/android/ui/reader/ReaderAnim.java index b807f8a28ff8..c99d4458584d 100644 --- a/src/org/wordpress/android/ui/reader/ReaderAnim.java +++ b/src/org/wordpress/android/ui/reader/ReaderAnim.java @@ -169,9 +169,9 @@ private static void animateButton(final View target, ReaderButton button) { } public static void animateListItem(ListView listView, - int positionAbsolute, - Animation.AnimationListener listener, - int animResId) { + int positionAbsolute, + Animation.AnimationListener listener, + int animResId) { if (listView == null) { return; } @@ -187,6 +187,8 @@ public static void animateListItem(ListView listView, } Animation animation = AnimationUtils.loadAnimation(listView.getContext(), animResId); + animation.setFillAfter(false); + if (listener != null) { animation.setAnimationListener(listener); } diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 8a565961488a..646cb8976215 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -8,6 +8,7 @@ import android.os.Parcelable; import android.text.Html; import android.text.TextUtils; +import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -24,10 +25,13 @@ import android.widget.RelativeLayout; import android.widget.TextView; +import com.cocosw.undobar.UndoBarController; + import org.wordpress.android.R; import org.wordpress.android.datasets.ReaderPostTable; import org.wordpress.android.datasets.ReaderTagTable; import org.wordpress.android.models.ReaderPost; +import org.wordpress.android.models.ReaderPostList; import org.wordpress.android.models.ReaderTag; import org.wordpress.android.models.ReaderTagType; import org.wordpress.android.ui.PullToRefreshHelper; @@ -37,6 +41,7 @@ import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType; import org.wordpress.android.ui.reader.actions.ReaderActions; import org.wordpress.android.ui.reader.actions.ReaderActions.RequestDataAction; +import org.wordpress.android.ui.reader.actions.ReaderBlogActions; import org.wordpress.android.ui.reader.actions.ReaderPostActions; import org.wordpress.android.ui.reader.actions.ReaderTagActions; import org.wordpress.android.ui.reader.actions.ReaderTagActions.TagAction; @@ -93,6 +98,7 @@ public static interface OnTagSelectedListener { private long mCurrentBlogId; private String mCurrentBlogUrl; private ReaderPostListType mPostListType; + private int mContextMenuListItemPosition; private boolean mIsUpdating; private boolean mIsFlinging; @@ -240,6 +246,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.reader_fragment_post_list, container, false); mListView = (WPListView) rootView.findViewById(android.R.id.list); + registerForContextMenu(mListView); + // bar that appears at top when new posts are downloaded mNewPostsBar = (TextView) rootView.findViewById(R.id.text_new_posts); mNewPostsBar.setVisibility(View.GONE); @@ -447,6 +455,79 @@ public boolean onOptionsItemSelected(MenuItem item) { } } + private static final int CONTEXT_MENU_BLOCK_BLOG = 1; + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + mContextMenuListItemPosition = info.position; + menu.add(0, CONTEXT_MENU_BLOCK_BLOG, 0, R.string.reader_menu_block_blog); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case CONTEXT_MENU_BLOCK_BLOG : + ReaderPost post = (ReaderPost) getPostAdapter().getItem(mContextMenuListItemPosition); + if (post != null) { + blockBlog(post.blogId, post.getBlogName()); + } + return true; + default : + return super.onContextItemSelected(item); + } + } + + private void blockBlog(final long blogId, final String blogName) { + if (!NetworkUtils.checkConnection(getActivity())) { + return; + } + + // remember the posts that we're about to delete so they can be restored upon undo + final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, ReaderConstants.READER_MAX_POSTS_TO_DISPLAY); + + if (!ReaderBlogActions.blockBlogFromReader(blogId)) { + return; + } + + // fade out the post the user chose to block from, then refresh the list + Animation.AnimationListener aniListener = new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { } + @Override + public void onAnimationRepeat(Animation animation) { } + @Override + public void onAnimationEnd(Animation animation) { + if (hasActivity()) { + refreshPosts(); + } + } + }; + ReaderAnim.animateListItem(mListView, mContextMenuListItemPosition, aniListener, R.anim.fade_out); + + // show the undo bar enabling the user to undo the block + UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { + @Override + public void onUndo(Parcelable parcelable) { + if (ReaderBlogActions.unblockBlogFromReader(blogId)) { + ReaderPostTable.addOrUpdatePosts(getCurrentTag(), postsToRestore); + refreshPosts(); + } + } + }; + new UndoBarController.UndoBar(getActivity()) + .message(getString(R.string.reader_toast_blog_blocked, blogName)) + .listener(undoListener) + .translucent(true) + .show(); + } + + private void hideUndoBar() { + if (hasActivity()) { + UndoBarController.clear(getActivity()); + } + } + /* * show/hide progress bar which appears at the bottom of the activity when loading more posts */ @@ -707,6 +788,7 @@ && getPostAdapter().isCurrentTag(tag)) { getPostAdapter().setCurrentTag(tag); hideNewPostsBar(); + hideUndoBar(); updateTagPreviewHeader(); hideLoadingProgress(); diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index b312e4cef183..1a8603acfd2d 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -381,4 +381,26 @@ public void onErrorResponse(VolleyError volleyError) { errorListener); WordPress.requestQueue.add(request); } + + public static boolean blockBlogFromReader(final long blogId) { + if (blogId == 0) { + return false; + } + + ReaderPostTable.deletePostsInBlog(blogId); + + // TODO: add API call + + return true; + } + + public static boolean unblockBlogFromReader(final long blogId) { + if (blogId == 0) { + return false; + } + + // TODO: add API call + + return true; + } } diff --git a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index c6a72af671ba..5938b4fdec5f 100644 --- a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -15,6 +15,7 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader; +import com.cocosw.undobar.UndoBarController; import org.wordpress.android.R; import org.wordpress.android.WordPress; @@ -226,9 +227,16 @@ public int getCount() { return mPosts.size(); } + public boolean isValidPosition(int position) { + return (position >= 0 && position < getCount()); + } @Override public Object getItem(int position) { - return mPosts.get(position); + if (isValidPosition(position)) { + return mPosts.get(position); + } else { + return null; + } } @Override @@ -386,13 +394,14 @@ public void onClick(View v) { holder.imgBtnReblog.setVisibility(View.INVISIBLE); } - // dropdown arrow only shows for wp posts in followed tags - if (post.isWP() && getPostListType() == ReaderPostListType.TAG_FOLLOWED) { + // dropdown arrow which displays "block this blog" menu only shows for public + // wp posts in followed tags + if (post.isWP() && !post.isPrivate && getPostListType() == ReaderPostListType.TAG_FOLLOWED) { holder.imgDropDown.setVisibility(View.VISIBLE); holder.imgDropDown.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // TODO + v.showContextMenu(); } }); } else { From 71385ac4fe6aac777042a9f37683d0b0e4db16ed Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 27 Jun 2014 08:11:49 -0400 Subject: [PATCH 04/22] Changed undo text, now remembering tapped post before blocking blog --- res/values/strings.xml | 2 +- .../ui/reader/ReaderPostListFragment.java | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 1f47f4e83738..a3699953e5e7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -651,7 +651,7 @@ You already follow this blog Unable to follow this blog Unable to unfollow this blog - Posts from %s will no longer appear + Posts from this blog will no longer appear No posts with this tag diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 646cb8976215..709f51302c65 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -98,7 +98,9 @@ public static interface OnTagSelectedListener { private long mCurrentBlogId; private String mCurrentBlogUrl; private ReaderPostListType mPostListType; + private int mContextMenuListItemPosition; + private ReaderPost mContextMenuPost; private boolean mIsUpdating; private boolean mIsFlinging; @@ -461,30 +463,33 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMen super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; mContextMenuListItemPosition = info.position; - menu.add(0, CONTEXT_MENU_BLOCK_BLOG, 0, R.string.reader_menu_block_blog); + mContextMenuPost = (ReaderPost) getPostAdapter().getItem(mContextMenuListItemPosition); + if (mContextMenuPost != null) { + if (mContextMenuPost.hasBlogName()) { + menu.setHeaderTitle(mContextMenuPost.getBlogName()); + } + menu.add(0, CONTEXT_MENU_BLOCK_BLOG, 0, R.string.reader_menu_block_blog); + } } @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case CONTEXT_MENU_BLOCK_BLOG : - ReaderPost post = (ReaderPost) getPostAdapter().getItem(mContextMenuListItemPosition); - if (post != null) { - blockBlog(post.blogId, post.getBlogName()); - } + blockBlog(mContextMenuPost.blogId); return true; default : return super.onContextItemSelected(item); } } - private void blockBlog(final long blogId, final String blogName) { + private void blockBlog(final long blogId) { if (!NetworkUtils.checkConnection(getActivity())) { return; } // remember the posts that we're about to delete so they can be restored upon undo - final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, ReaderConstants.READER_MAX_POSTS_TO_DISPLAY); + final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, 0); if (!ReaderBlogActions.blockBlogFromReader(blogId)) { return; @@ -516,7 +521,7 @@ public void onUndo(Parcelable parcelable) { } }; new UndoBarController.UndoBar(getActivity()) - .message(getString(R.string.reader_toast_blog_blocked, blogName)) + .message(getString(R.string.reader_toast_blog_blocked)) .listener(undoListener) .translucent(true) .show(); From 4cdef1a40b9cf4858f73ef687ffe1fae5c895762 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 27 Jun 2014 16:19:40 -0400 Subject: [PATCH 05/22] API calls to block/unblock are now coded (untested) --- .../android/datasets/ReaderPostTable.java | 3 +- .../ui/reader/ReaderPostListFragment.java | 15 +++--- .../ui/reader/actions/ReaderBlogActions.java | 54 +++++++++++++++---- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/org/wordpress/android/datasets/ReaderPostTable.java b/src/org/wordpress/android/datasets/ReaderPostTable.java index 12d299534300..a44eb942bbe8 100644 --- a/src/org/wordpress/android/datasets/ReaderPostTable.java +++ b/src/org/wordpress/android/datasets/ReaderPostTable.java @@ -412,8 +412,7 @@ public static void addOrUpdatePosts(final ReaderTag tag, ReaderPostList posts) { stmtPosts.clearBindings(); } - // now add to tbl_post_tags - note that tagName will be null when updating a single - // post, in which case we skip it here + // now add to tbl_post_tags if a tag was passed if (tag != null) { String tagName = tag.getTagName(); int tagType = tag.tagType.toInt(); diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 709f51302c65..7e6b43cd816a 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -488,14 +488,12 @@ private void blockBlog(final long blogId) { return; } - // remember the posts that we're about to delete so they can be restored upon undo - final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, 0); + // perform call to block this blog - returns list of posts deleted by blocking so + // they can be restored if the user undoes the block + final ReaderPostList postsToRestore = ReaderBlogActions.blockBlogFromReader(blogId); - if (!ReaderBlogActions.blockBlogFromReader(blogId)) { - return; - } - - // fade out the post the user chose to block from, then refresh the list + // fade out the post the user chose to block from, then refresh the list so the posts + // deleted by the above call no longer appear Animation.AnimationListener aniListener = new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @@ -514,8 +512,7 @@ public void onAnimationEnd(Animation animation) { UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { @Override public void onUndo(Parcelable parcelable) { - if (ReaderBlogActions.unblockBlogFromReader(blogId)) { - ReaderPostTable.addOrUpdatePosts(getCurrentTag(), postsToRestore); + if (ReaderBlogActions.unblockBlogFromReader(blogId, postsToRestore)) { refreshPosts(); } } diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index 1a8603acfd2d..910c78028b1c 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -17,6 +17,7 @@ import org.wordpress.android.models.ReaderBlog; import org.wordpress.android.models.ReaderBlogList; import org.wordpress.android.models.ReaderPost; +import org.wordpress.android.models.ReaderPostList; import org.wordpress.android.models.ReaderRecommendBlogList; import org.wordpress.android.ui.reader.ReaderConstants; import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateBlogInfoListener; @@ -382,24 +383,59 @@ public void onErrorResponse(VolleyError volleyError) { WordPress.requestQueue.add(request); } - public static boolean blockBlogFromReader(final long blogId) { + /* + * block a blog - returns the list of posts that were deleted by the block so they can + * be restored if the user undoes the block + */ + public static ReaderPostList blockBlogFromReader(final long blogId) { if (blogId == 0) { - return false; + return null; } + // remember the posts in this blog, then delete them + final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, 0); ReaderPostTable.deletePostsInBlog(blogId); - // TODO: add API call + com.wordpress.rest.RestRequest.Listener listener = new RestRequest.Listener() { + @Override + public void onResponse(JSONObject jsonObject) { + boolean success = (jsonObject != null && jsonObject.optBoolean("success")); + if (!success) { + ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + } + } + }; + RestRequest.ErrorListener errorListener = new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError volleyError) { + AppLog.e(T.READER, volleyError); + ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + } + }; - return true; + String path = "/me/block/sites/" + Long.toString(blogId) + "/new"; + WordPress.getRestClientUtils().post(path, listener, errorListener); + + return postsToRestore; } - public static boolean unblockBlogFromReader(final long blogId) { - if (blogId == 0) { - return false; - } + public static boolean unblockBlogFromReader(final long blogId, final ReaderPostList postsToRestore) { + ReaderPostTable.addOrUpdatePosts(null, postsToRestore); - // TODO: add API call + com.wordpress.rest.RestRequest.Listener listener = new RestRequest.Listener() { + @Override + public void onResponse(JSONObject jsonObject) { + // nop + } + }; + RestRequest.ErrorListener errorListener = new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError volleyError) { + AppLog.e(T.READER, volleyError); + } + }; + String path = "/me/block/sites/" + Long.toString(blogId) + "/delete"; + WordPress.getRestClientUtils().post(path, listener, errorListener); return true; } From 57078ba5485cfab3972e1fedbd4f284b78b2cedb Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 27 Jun 2014 17:41:52 -0400 Subject: [PATCH 06/22] Reworded undo text --- res/values/strings.xml | 2 +- .../android/ui/reader/actions/ReaderBlogActions.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index a3699953e5e7..c3042fb11723 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -651,7 +651,7 @@ You already follow this blog Unable to follow this blog Unable to unfollow this blog - Posts from this blog will no longer appear + Posts from this blog will no longer be shown No posts with this tag diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index 910c78028b1c..0a86207ce05c 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -393,7 +393,7 @@ public static ReaderPostList blockBlogFromReader(final long blogId) { } // remember the posts in this blog, then delete them - final ReaderPostList postsToRestore = ReaderPostTable.getPostsInBlog(blogId, 0); + final ReaderPostList deletedPosts = ReaderPostTable.getPostsInBlog(blogId, 0); ReaderPostTable.deletePostsInBlog(blogId); com.wordpress.rest.RestRequest.Listener listener = new RestRequest.Listener() { @@ -401,7 +401,7 @@ public static ReaderPostList blockBlogFromReader(final long blogId) { public void onResponse(JSONObject jsonObject) { boolean success = (jsonObject != null && jsonObject.optBoolean("success")); if (!success) { - ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + ReaderPostTable.addOrUpdatePosts(null, deletedPosts); } } }; @@ -409,14 +409,14 @@ public void onResponse(JSONObject jsonObject) { @Override public void onErrorResponse(VolleyError volleyError) { AppLog.e(T.READER, volleyError); - ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + ReaderPostTable.addOrUpdatePosts(null, deletedPosts); } }; String path = "/me/block/sites/" + Long.toString(blogId) + "/new"; WordPress.getRestClientUtils().post(path, listener, errorListener); - return postsToRestore; + return deletedPosts; } public static boolean unblockBlogFromReader(final long blogId, final ReaderPostList postsToRestore) { From 07d2b4825f436279b5bfc04fb8c14248f2c6d691 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 27 Jun 2014 17:53:43 -0400 Subject: [PATCH 07/22] Rewrote ReaderAnim.animateListItem() to use predefined styles --- ...er_tag_add.xml => reader_listitem_add.xml} | 0 ..._delete.xml => reader_listitem_delete.xml} | 0 .../android/ui/reader/ReaderAnim.java | 19 +++++++++++++++++-- .../ui/reader/ReaderPostListFragment.java | 2 +- .../android/ui/reader/ReaderTagFragment.java | 4 ++-- 5 files changed, 20 insertions(+), 5 deletions(-) rename res/anim/{reader_tag_add.xml => reader_listitem_add.xml} (100%) rename res/anim/{reader_tag_delete.xml => reader_listitem_delete.xml} (100%) diff --git a/res/anim/reader_tag_add.xml b/res/anim/reader_listitem_add.xml similarity index 100% rename from res/anim/reader_tag_add.xml rename to res/anim/reader_listitem_add.xml diff --git a/res/anim/reader_tag_delete.xml b/res/anim/reader_listitem_delete.xml similarity index 100% rename from res/anim/reader_tag_delete.xml rename to res/anim/reader_listitem_delete.xml diff --git a/src/org/wordpress/android/ui/reader/ReaderAnim.java b/src/org/wordpress/android/ui/reader/ReaderAnim.java index c99d4458584d..5b8ebf07ea65 100644 --- a/src/org/wordpress/android/ui/reader/ReaderAnim.java +++ b/src/org/wordpress/android/ui/reader/ReaderAnim.java @@ -13,6 +13,8 @@ import android.view.animation.LinearInterpolator; import android.widget.ListView; +import org.wordpress.android.R; + public class ReaderAnim { public static enum Duration { @@ -168,10 +170,11 @@ private static void animateButton(final View target, ReaderButton button) { set.start(); } + public static enum AnimateListItemStyle { ADDITION, DELETION } public static void animateListItem(ListView listView, int positionAbsolute, - Animation.AnimationListener listener, - int animResId) { + AnimateListItemStyle style, + Animation.AnimationListener listener) { if (listView == null) { return; } @@ -186,6 +189,18 @@ public static void animateListItem(ListView listView, return; } + final int animResId; + switch (style) { + case ADDITION: + animResId = R.anim.reader_listitem_add; + break; + case DELETION: + animResId = R.anim.reader_listitem_delete; + break; + default: + return; + } + Animation animation = AnimationUtils.loadAnimation(listView.getContext(), animResId); animation.setFillAfter(false); diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 7e6b43cd816a..197a92d95018 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -506,7 +506,7 @@ public void onAnimationEnd(Animation animation) { } } }; - ReaderAnim.animateListItem(mListView, mContextMenuListItemPosition, aniListener, R.anim.fade_out); + ReaderAnim.animateListItem(mListView, mContextMenuListItemPosition, ReaderAnim.AnimateListItemStyle.DELETION, aniListener); // show the undo bar enabling the user to undo the block UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { diff --git a/src/org/wordpress/android/ui/reader/ReaderTagFragment.java b/src/org/wordpress/android/ui/reader/ReaderTagFragment.java index d31c2d753ca0..c1edbba3f038 100644 --- a/src/org/wordpress/android/ui/reader/ReaderTagFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderTagFragment.java @@ -172,8 +172,8 @@ public void onAnimationEnd(Animation animation) { refresh(); } }; - int aniResId = (action == TagAction.ADD ? R.anim.reader_tag_add : R.anim.reader_tag_delete); - ReaderAnim.animateListItem(mListView, index, aniListener, aniResId); + ReaderAnim.AnimateListItemStyle animStyle = (action == TagAction.ADD ? ReaderAnim.AnimateListItemStyle.ADDITION : ReaderAnim.AnimateListItemStyle.DELETION); + ReaderAnim.animateListItem(mListView, index, animStyle, aniListener); } else { refresh(); } From fe367963967bf5b8e86906b5585594234a435536 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Fri, 27 Jun 2014 21:46:27 -0400 Subject: [PATCH 08/22] Added comment header --- src/org/wordpress/android/ui/reader/ReaderAnim.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/org/wordpress/android/ui/reader/ReaderAnim.java b/src/org/wordpress/android/ui/reader/ReaderAnim.java index 5b8ebf07ea65..3b593d0cb271 100644 --- a/src/org/wordpress/android/ui/reader/ReaderAnim.java +++ b/src/org/wordpress/android/ui/reader/ReaderAnim.java @@ -170,6 +170,9 @@ private static void animateButton(final View target, ReaderButton button) { set.start(); } + /* + * called when adding or removing an item from a listView + */ public static enum AnimateListItemStyle { ADDITION, DELETION } public static void animateListItem(ListView listView, int positionAbsolute, From 77668456698b604c67dfe69f0988d8dc60d2ab66 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 30 Jun 2014 15:52:28 -0400 Subject: [PATCH 09/22] Added ActionListener to block/unblock blog --- res/values/strings.xml | 1 + .../ui/reader/ReaderPostListFragment.java | 13 ++++++-- .../ui/reader/actions/ReaderBlogActions.java | 32 ++++++++++++++----- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index c3042fb11723..94b43d9c0ed1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -652,6 +652,7 @@ Unable to follow this blog Unable to unfollow this blog Posts from this blog will no longer be shown + Unable to perform this action No posts with this tag diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 197a92d95018..bdc168bc4b91 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -488,9 +488,18 @@ private void blockBlog(final long blogId) { return; } + final ReaderActions.ActionListener actionListener = new ReaderActions.ActionListener() { + @Override + public void onActionResult(boolean succeeded) { + if (!succeeded) { + ToastUtils.showToast(getActivity(), R.string.reader_toast_err_generic); + } + } + }; + // perform call to block this blog - returns list of posts deleted by blocking so // they can be restored if the user undoes the block - final ReaderPostList postsToRestore = ReaderBlogActions.blockBlogFromReader(blogId); + final ReaderPostList postsToRestore = ReaderBlogActions.blockBlogFromReader(blogId, actionListener); // fade out the post the user chose to block from, then refresh the list so the posts // deleted by the above call no longer appear @@ -512,7 +521,7 @@ public void onAnimationEnd(Animation animation) { UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { @Override public void onUndo(Parcelable parcelable) { - if (ReaderBlogActions.unblockBlogFromReader(blogId, postsToRestore)) { + if (ReaderBlogActions.unblockBlogFromReader(blogId, postsToRestore, actionListener)) { refreshPosts(); } } diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index 0a86207ce05c..2fd13c46c9bc 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -387,12 +387,8 @@ public void onErrorResponse(VolleyError volleyError) { * block a blog - returns the list of posts that were deleted by the block so they can * be restored if the user undoes the block */ - public static ReaderPostList blockBlogFromReader(final long blogId) { - if (blogId == 0) { - return null; - } - - // remember the posts in this blog, then delete them + public static ReaderPostList blockBlogFromReader(final long blogId, + final ReaderActions.ActionListener actionListener) { final ReaderPostList deletedPosts = ReaderPostTable.getPostsInBlog(blogId, 0); ReaderPostTable.deletePostsInBlog(blogId); @@ -401,8 +397,13 @@ public static ReaderPostList blockBlogFromReader(final long blogId) { public void onResponse(JSONObject jsonObject) { boolean success = (jsonObject != null && jsonObject.optBoolean("success")); if (!success) { + AppLog.w(T.READER, "failed to block blog"); ReaderPostTable.addOrUpdatePosts(null, deletedPosts); } + if (actionListener != null) { + actionListener.onActionResult(success); + } + } }; RestRequest.ErrorListener errorListener = new RestRequest.ErrorListener() { @@ -410,6 +411,9 @@ public void onResponse(JSONObject jsonObject) { public void onErrorResponse(VolleyError volleyError) { AppLog.e(T.READER, volleyError); ReaderPostTable.addOrUpdatePosts(null, deletedPosts); + if (actionListener != null) { + actionListener.onActionResult(false); + } } }; @@ -419,19 +423,31 @@ public void onErrorResponse(VolleyError volleyError) { return deletedPosts; } - public static boolean unblockBlogFromReader(final long blogId, final ReaderPostList postsToRestore) { + public static boolean unblockBlogFromReader(final long blogId, + final ReaderPostList postsToRestore, + final ReaderActions.ActionListener actionListener) { ReaderPostTable.addOrUpdatePosts(null, postsToRestore); com.wordpress.rest.RestRequest.Listener listener = new RestRequest.Listener() { @Override public void onResponse(JSONObject jsonObject) { - // nop + boolean success = (jsonObject != null && jsonObject.optBoolean("success")); + if (!success) { + AppLog.w(T.READER, "failed to unblock blog"); + } + if (actionListener != null) { + actionListener.onActionResult(success); + } + } }; RestRequest.ErrorListener errorListener = new RestRequest.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { AppLog.e(T.READER, volleyError); + if (actionListener != null) { + actionListener.onActionResult(false); + } } }; String path = "/me/block/sites/" + Long.toString(blogId) + "/delete"; From be3b7d5a1c7173b0f38bffa09fb50b9089342f84 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 30 Jun 2014 15:57:41 -0400 Subject: [PATCH 10/22] Added missing hasActivity() --- src/org/wordpress/android/ui/reader/ReaderPostListFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index bdc168bc4b91..43f052f40408 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -491,7 +491,7 @@ private void blockBlog(final long blogId) { final ReaderActions.ActionListener actionListener = new ReaderActions.ActionListener() { @Override public void onActionResult(boolean succeeded) { - if (!succeeded) { + if (!succeeded && hasActivity()) { ToastUtils.showToast(getActivity(), R.string.reader_toast_err_generic); } } From 20ecb01579e7c043718ca9981193313146f1c4a0 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 30 Jun 2014 16:22:55 -0400 Subject: [PATCH 11/22] Changed blocking animation --- res/anim/reader_listitem_block.xml | 12 ++++++++++++ res/anim/reader_listview_row.xml | 8 -------- src/org/wordpress/android/ui/reader/ReaderAnim.java | 5 ++++- .../android/ui/reader/ReaderPostListFragment.java | 5 ++++- 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 res/anim/reader_listitem_block.xml delete mode 100644 res/anim/reader_listview_row.xml diff --git a/res/anim/reader_listitem_block.xml b/res/anim/reader_listitem_block.xml new file mode 100644 index 000000000000..0eff04bc2b2d --- /dev/null +++ b/res/anim/reader_listitem_block.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/res/anim/reader_listview_row.xml b/res/anim/reader_listview_row.xml deleted file mode 100644 index 50fdd080c412..000000000000 --- a/res/anim/reader_listview_row.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/src/org/wordpress/android/ui/reader/ReaderAnim.java b/src/org/wordpress/android/ui/reader/ReaderAnim.java index 3b593d0cb271..9268e65e9f31 100644 --- a/src/org/wordpress/android/ui/reader/ReaderAnim.java +++ b/src/org/wordpress/android/ui/reader/ReaderAnim.java @@ -173,7 +173,7 @@ private static void animateButton(final View target, ReaderButton button) { /* * called when adding or removing an item from a listView */ - public static enum AnimateListItemStyle { ADDITION, DELETION } + public static enum AnimateListItemStyle { ADDITION, DELETION, BLOCK } public static void animateListItem(ListView listView, int positionAbsolute, AnimateListItemStyle style, @@ -200,6 +200,9 @@ public static void animateListItem(ListView listView, case DELETION: animResId = R.anim.reader_listitem_delete; break; + case BLOCK: + animResId = R.anim.reader_listitem_block; + break; default: return; } diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 43f052f40408..8fdfd09e653c 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -515,7 +515,10 @@ public void onAnimationEnd(Animation animation) { } } }; - ReaderAnim.animateListItem(mListView, mContextMenuListItemPosition, ReaderAnim.AnimateListItemStyle.DELETION, aniListener); + ReaderAnim.animateListItem(mListView, + mContextMenuListItemPosition, + ReaderAnim.AnimateListItemStyle.BLOCK, + aniListener); // show the undo bar enabling the user to undo the block UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { From a129317e0f943cef6a722ae21fb3dbe70952ffd4 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 30 Jun 2014 16:40:48 -0400 Subject: [PATCH 12/22] Changed blocking animation (again) and now removing list item after blocking --- res/anim/reader_listitem_block.xml | 18 ++++++++++-------- .../android/ui/reader/ReaderAnim.java | 1 - .../ui/reader/ReaderPostListFragment.java | 4 ++-- .../ui/reader/adapters/ReaderPostAdapter.java | 8 +++++++- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/res/anim/reader_listitem_block.xml b/res/anim/reader_listitem_block.xml index 0eff04bc2b2d..480e5e2f9183 100644 --- a/res/anim/reader_listitem_block.xml +++ b/res/anim/reader_listitem_block.xml @@ -1,12 +1,14 @@ - \ No newline at end of file + android:interpolator="@android:anim/accelerate_interpolator"> + + \ No newline at end of file diff --git a/src/org/wordpress/android/ui/reader/ReaderAnim.java b/src/org/wordpress/android/ui/reader/ReaderAnim.java index 9268e65e9f31..923c0ea99ce4 100644 --- a/src/org/wordpress/android/ui/reader/ReaderAnim.java +++ b/src/org/wordpress/android/ui/reader/ReaderAnim.java @@ -208,7 +208,6 @@ public static void animateListItem(ListView listView, } Animation animation = AnimationUtils.loadAnimation(listView.getContext(), animResId); - animation.setFillAfter(false); if (listener != null) { animation.setAnimationListener(listener); diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 8fdfd09e653c..4c9d9ca0cfd6 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -501,7 +501,7 @@ public void onActionResult(boolean succeeded) { // they can be restored if the user undoes the block final ReaderPostList postsToRestore = ReaderBlogActions.blockBlogFromReader(blogId, actionListener); - // fade out the post the user chose to block from, then refresh the list so the posts + // animate out the post the user chose to block from, then refresh the list so the posts // deleted by the above call no longer appear Animation.AnimationListener aniListener = new Animation.AnimationListener() { @Override @@ -511,7 +511,7 @@ public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (hasActivity()) { - refreshPosts(); + getPostAdapter().removePost(mContextMenuListItemPosition); } } }; diff --git a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index 5938b4fdec5f..97d3ee2026cc 100644 --- a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -15,7 +15,6 @@ import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader; -import com.cocosw.undobar.UndoBarController; import org.wordpress.android.R; import org.wordpress.android.WordPress; @@ -154,6 +153,13 @@ public void reload() { loadPosts(); } + public void removePost(int position) { + if (isValidPosition(position)) { + mPosts.remove(position); + notifyDataSetChanged(); + } + } + /* * reload a single post */ From fac4eafd03d175fc45918770b86f596f93193c34 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Mon, 30 Jun 2014 17:43:44 -0400 Subject: [PATCH 13/22] Increased padding around dropdown icon --- res/layout/reader_listitem_post_excerpt.xml | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/res/layout/reader_listitem_post_excerpt.xml b/res/layout/reader_listitem_post_excerpt.xml index 4b2f33349347..c0487fd20890 100644 --- a/res/layout/reader_listitem_post_excerpt.xml +++ b/res/layout/reader_listitem_post_excerpt.xml @@ -6,16 +6,16 @@ + android:layout_height="wrap_content" + android:background="@drawable/reader_postlist_selector"> + android:background="@drawable/reader_transparent_selector" + android:paddingBottom="@dimen/margin_large"> + android:textSize="@dimen/text_sz_medium" + tools:text="text_blog_name" /> @@ -69,9 +72,9 @@ android:id="@+id/text_title" style="@style/ReaderTextView.Post.Title" android:layout_below="@+id/image_featured" - android:layout_marginTop="@dimen/margin_large" android:layout_marginLeft="@dimen/margin_large" android:layout_marginRight="@dimen/margin_large" + android:layout_marginTop="@dimen/margin_large" tools:text="text_title" /> Date: Tue, 1 Jul 2014 07:19:46 -0400 Subject: [PATCH 14/22] Changed to using a PopupMenu --- .../ui/reader/ReaderPostListFragment.java | 68 ++++++++++--------- .../ui/reader/adapters/ReaderPostAdapter.java | 12 +++- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 4c9d9ca0cfd6..cad9ba5bc8c3 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -8,7 +8,6 @@ import android.os.Parcelable; import android.text.Html; import android.text.TextUtils; -import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -21,6 +20,7 @@ import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ImageView; +import android.widget.PopupMenu; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; @@ -77,8 +77,13 @@ public static interface OnTagSelectedListener { public void onTagSelected(String tagName); } + public static interface OnPostPopupListener { + public void onShowPostPopup(View view, ReaderPost post, int position); + } + private ReaderActionBarTagAdapter mActionBarAdapter; private ReaderPostAdapter mPostAdapter; + private OnPostSelectedListener mPostSelectedListener; private OnTagSelectedListener mOnTagSelectedListener; @@ -99,9 +104,6 @@ public static interface OnTagSelectedListener { private String mCurrentBlogUrl; private ReaderPostListType mPostListType; - private int mContextMenuListItemPosition; - private ReaderPost mContextMenuPost; - private boolean mIsUpdating; private boolean mIsFlinging; private boolean mWasPaused; @@ -248,8 +250,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa final ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.reader_fragment_post_list, container, false); mListView = (WPListView) rootView.findViewById(android.R.id.list); - registerForContextMenu(mListView); - // bar that appears at top when new posts are downloaded mNewPostsBar = (TextView) rootView.findViewById(R.id.text_new_posts); mNewPostsBar.setVisibility(View.GONE); @@ -434,6 +434,7 @@ public void onActivityCreated(Bundle savedInstanceState) { } getPostAdapter().setOnTagSelectedListener(mOnTagSelectedListener); + getPostAdapter().setOnPostPopupListener(mOnPostPopupListener); } @Override @@ -457,33 +458,32 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - private static final int CONTEXT_MENU_BLOCK_BLOG = 1; - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - mContextMenuListItemPosition = info.position; - mContextMenuPost = (ReaderPost) getPostAdapter().getItem(mContextMenuListItemPosition); - if (mContextMenuPost != null) { - if (mContextMenuPost.hasBlogName()) { - menu.setHeaderTitle(mContextMenuPost.getBlogName()); + + /* + * called when user taps dropdown arrow icon next to a post - shows a popup menu + * that enables blocking the blog the post is in + */ + private final OnPostPopupListener mOnPostPopupListener = new OnPostPopupListener() { + @Override + public void onShowPostPopup(View view, final ReaderPost post, final int position) { + if (view == null || post == null) { + return; } - menu.add(0, CONTEXT_MENU_BLOCK_BLOG, 0, R.string.reader_menu_block_blog); - } - } - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (item.getItemId()) { - case CONTEXT_MENU_BLOCK_BLOG : - blockBlog(mContextMenuPost.blogId); - return true; - default : - return super.onContextItemSelected(item); + PopupMenu popup = new PopupMenu(getActivity(), view); + MenuItem menuItem = popup.getMenu().add(getString(R.string.reader_menu_block_blog)); + menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + blockBlogForPost(post, position); + return true; + } + }); + popup.show(); } - } + }; - private void blockBlog(final long blogId) { + private void blockBlogForPost(final ReaderPost post, final int position) { if (!NetworkUtils.checkConnection(getActivity())) { return; } @@ -492,6 +492,7 @@ private void blockBlog(final long blogId) { @Override public void onActionResult(boolean succeeded) { if (!succeeded && hasActivity()) { + hideUndoBar(); ToastUtils.showToast(getActivity(), R.string.reader_toast_err_generic); } } @@ -499,7 +500,8 @@ public void onActionResult(boolean succeeded) { // perform call to block this blog - returns list of posts deleted by blocking so // they can be restored if the user undoes the block - final ReaderPostList postsToRestore = ReaderBlogActions.blockBlogFromReader(blogId, actionListener); + final ReaderPostList postsToRestore = + ReaderBlogActions.blockBlogFromReader(post.blogId, actionListener); // animate out the post the user chose to block from, then refresh the list so the posts // deleted by the above call no longer appear @@ -511,12 +513,12 @@ public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { if (hasActivity()) { - getPostAdapter().removePost(mContextMenuListItemPosition); + getPostAdapter().removePost(position); } } }; ReaderAnim.animateListItem(mListView, - mContextMenuListItemPosition, + position, ReaderAnim.AnimateListItemStyle.BLOCK, aniListener); @@ -524,7 +526,7 @@ public void onAnimationEnd(Animation animation) { UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { @Override public void onUndo(Parcelable parcelable) { - if (ReaderBlogActions.unblockBlogFromReader(blogId, postsToRestore, actionListener)) { + if (ReaderBlogActions.unblockBlogFromReader(post.blogId, postsToRestore, actionListener)) { refreshPosts(); } } diff --git a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index 97d3ee2026cc..d862803baaa4 100644 --- a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -25,6 +25,7 @@ import org.wordpress.android.ui.reader.ReaderActivityLauncher; import org.wordpress.android.ui.reader.ReaderAnim; import org.wordpress.android.ui.reader.ReaderConstants; +import org.wordpress.android.ui.reader.ReaderPostListFragment.OnPostPopupListener; import org.wordpress.android.ui.reader.ReaderPostListFragment.OnTagSelectedListener; import org.wordpress.android.ui.reader.ReaderTypes; import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType; @@ -66,6 +67,7 @@ public class ReaderPostAdapter extends BaseAdapter { private ReaderPostList mPosts = new ReaderPostList(); private OnTagSelectedListener mOnTagSelectedListener; + private OnPostPopupListener mOnPostPopupListener; private final ReaderActions.RequestReblogListener mReblogListener; private final ReaderActions.DataLoadedListener mDataLoadedListener; private final ReaderActions.DataRequestedListener mDataRequestedListener; @@ -109,6 +111,10 @@ public void setOnTagSelectedListener(OnTagSelectedListener listener) { mOnTagSelectedListener = listener; } + public void setOnPostPopupListener(OnPostPopupListener onPostPopupListener) { + mOnPostPopupListener = onPostPopupListener; + } + ReaderPostListType getPostListType() { return (mPostListType != null ? mPostListType : ReaderTypes.DEFAULT_POST_LIST_TYPE); } @@ -406,8 +412,10 @@ public void onClick(View v) { holder.imgDropDown.setVisibility(View.VISIBLE); holder.imgDropDown.setOnClickListener(new View.OnClickListener() { @Override - public void onClick(View v) { - v.showContextMenu(); + public void onClick(View view) { + if (mOnPostPopupListener != null) { + mOnPostPopupListener.onShowPostPopup(view, post, position); + } } }); } else { From 2054648bd7d6da27998012f5e06879d38c9ec0e1 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 1 Jul 2014 10:11:27 -0400 Subject: [PATCH 15/22] Added logging, changed checkBlogUrlReachable to use HEAD request --- .../android/ui/reader/ReaderPostListFragment.java | 2 ++ .../ui/reader/actions/ReaderBlogActions.java | 15 ++++++++++----- .../ui/reader/adapters/ReaderPostAdapter.java | 7 ++++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index cad9ba5bc8c3..17d959cf34f0 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -488,6 +488,8 @@ private void blockBlogForPost(final ReaderPost post, final int position) { return; } + AppLog.i(T.READER, "blocking blog " + post.blogId); + final ReaderActions.ActionListener actionListener = new ReaderActions.ActionListener() { @Override public void onActionResult(boolean succeeded) { diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index 2fd13c46c9bc..2bad653e4d57 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -374,9 +374,9 @@ public void onErrorResponse(VolleyError volleyError) { } }; - // TODO: this should be a HEAD rather than GET request, but Volley doesn't support HEAD + // TODO: may be a leak here - http://stackoverflow.com/a/23549486/1673548 StringRequest request = new StringRequest( - Request.Method.GET, + Request.Method.HEAD, blogUrl, listener, errorListener); @@ -397,7 +397,7 @@ public static ReaderPostList blockBlogFromReader(final long blogId, public void onResponse(JSONObject jsonObject) { boolean success = (jsonObject != null && jsonObject.optBoolean("success")); if (!success) { - AppLog.w(T.READER, "failed to block blog"); + AppLog.w(T.READER, "failed to block blog " + blogId); ReaderPostTable.addOrUpdatePosts(null, deletedPosts); } if (actionListener != null) { @@ -417,6 +417,7 @@ public void onErrorResponse(VolleyError volleyError) { } }; + AppLog.i(T.READER, "blocking blog " + blogId); String path = "/me/block/sites/" + Long.toString(blogId) + "/new"; WordPress.getRestClientUtils().post(path, listener, errorListener); @@ -426,14 +427,16 @@ public void onErrorResponse(VolleyError volleyError) { public static boolean unblockBlogFromReader(final long blogId, final ReaderPostList postsToRestore, final ReaderActions.ActionListener actionListener) { - ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + if (postsToRestore != null) { + ReaderPostTable.addOrUpdatePosts(null, postsToRestore); + } com.wordpress.rest.RestRequest.Listener listener = new RestRequest.Listener() { @Override public void onResponse(JSONObject jsonObject) { boolean success = (jsonObject != null && jsonObject.optBoolean("success")); if (!success) { - AppLog.w(T.READER, "failed to unblock blog"); + AppLog.w(T.READER, "failed to unblock blog " + blogId); } if (actionListener != null) { actionListener.onActionResult(success); @@ -450,6 +453,8 @@ public void onErrorResponse(VolleyError volleyError) { } } }; + + AppLog.i(T.READER, "unblocking blog " + blogId); String path = "/me/block/sites/" + Long.toString(blogId) + "/delete"; WordPress.getRestClientUtils().post(path, listener, errorListener); diff --git a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java index d862803baaa4..05d088b1de03 100644 --- a/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java +++ b/src/org/wordpress/android/ui/reader/adapters/ReaderPostAdapter.java @@ -265,10 +265,11 @@ public boolean hasStableIds() { public View getView(final int position, View convertView, final ViewGroup parent) { final ReaderPost post = (ReaderPost) getItem(position); final PostViewHolder holder; + ReaderPostListType postListType = getPostListType(); if (convertView == null) { convertView = mInflater.inflate(R.layout.reader_listitem_post_excerpt, parent, false); - holder = new PostViewHolder(convertView, getPostListType()); + holder = new PostViewHolder(convertView, postListType); convertView.setTag(holder); } else { holder = (PostViewHolder) convertView.getTag(); @@ -278,7 +279,7 @@ public View getView(final int position, View convertView, final ViewGroup parent holder.txtDate.setText(DateTimeUtils.javaDateToTimeSpan(post.getDatePublished())); // post header (avatar, blog name and follow button) only appears when showing tagged posts - if (getPostListType().isTagType()) { + if (postListType.isTagType()) { holder.imgAvatar.setImageUrl(post.getPostAvatarForDisplay(mAvatarSz), WPNetworkImageView.ImageType.AVATAR); if (post.hasBlogName()) { holder.txtBlogName.setText(post.getBlogName()); @@ -408,7 +409,7 @@ public void onClick(View v) { // dropdown arrow which displays "block this blog" menu only shows for public // wp posts in followed tags - if (post.isWP() && !post.isPrivate && getPostListType() == ReaderPostListType.TAG_FOLLOWED) { + if (post.isWP() && !post.isPrivate && postListType == ReaderPostListType.TAG_FOLLOWED) { holder.imgDropDown.setVisibility(View.VISIBLE); holder.imgDropDown.setOnClickListener(new View.OnClickListener() { @Override From 4415db9b671757f095714b75c6fe81074c3abde4 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 1 Jul 2014 10:29:58 -0400 Subject: [PATCH 16/22] Changed error message when blocking fails --- res/values/strings.xml | 1 + .../android/ui/reader/ReaderPostListFragment.java | 6 +++--- .../android/ui/reader/actions/ReaderBlogActions.java | 10 ++-------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 94b43d9c0ed1..cf11d731ee0a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -652,6 +652,7 @@ Unable to follow this blog Unable to unfollow this blog Posts from this blog will no longer be shown + Unable to block this blog Unable to perform this action diff --git a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java index 17d959cf34f0..71a693b6c408 100644 --- a/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java +++ b/src/org/wordpress/android/ui/reader/ReaderPostListFragment.java @@ -490,12 +490,12 @@ private void blockBlogForPost(final ReaderPost post, final int position) { AppLog.i(T.READER, "blocking blog " + post.blogId); - final ReaderActions.ActionListener actionListener = new ReaderActions.ActionListener() { + ReaderActions.ActionListener actionListener = new ReaderActions.ActionListener() { @Override public void onActionResult(boolean succeeded) { if (!succeeded && hasActivity()) { hideUndoBar(); - ToastUtils.showToast(getActivity(), R.string.reader_toast_err_generic); + ToastUtils.showToast(getActivity(), R.string.reader_toast_err_block_blog); } } }; @@ -528,7 +528,7 @@ public void onAnimationEnd(Animation animation) { UndoBarController.UndoListener undoListener = new UndoBarController.UndoListener() { @Override public void onUndo(Parcelable parcelable) { - if (ReaderBlogActions.unblockBlogFromReader(post.blogId, postsToRestore, actionListener)) { + if (ReaderBlogActions.unblockBlogFromReader(post.blogId, postsToRestore)) { refreshPosts(); } } diff --git a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java index 2bad653e4d57..d1cdc366fed5 100644 --- a/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java +++ b/src/org/wordpress/android/ui/reader/actions/ReaderBlogActions.java @@ -396,6 +396,7 @@ public static ReaderPostList blockBlogFromReader(final long blogId, @Override public void onResponse(JSONObject jsonObject) { boolean success = (jsonObject != null && jsonObject.optBoolean("success")); + // TODO: call always returns success=false for vip blogs if (!success) { AppLog.w(T.READER, "failed to block blog " + blogId); ReaderPostTable.addOrUpdatePosts(null, deletedPosts); @@ -425,8 +426,7 @@ public void onErrorResponse(VolleyError volleyError) { } public static boolean unblockBlogFromReader(final long blogId, - final ReaderPostList postsToRestore, - final ReaderActions.ActionListener actionListener) { + final ReaderPostList postsToRestore) { if (postsToRestore != null) { ReaderPostTable.addOrUpdatePosts(null, postsToRestore); } @@ -438,9 +438,6 @@ public void onResponse(JSONObject jsonObject) { if (!success) { AppLog.w(T.READER, "failed to unblock blog " + blogId); } - if (actionListener != null) { - actionListener.onActionResult(success); - } } }; @@ -448,9 +445,6 @@ public void onResponse(JSONObject jsonObject) { @Override public void onErrorResponse(VolleyError volleyError) { AppLog.e(T.READER, volleyError); - if (actionListener != null) { - actionListener.onActionResult(false); - } } }; From 34abdc4f271e10f3a3850fbf4c7e34ab66dd5876 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Tue, 1 Jul 2014 10:58:36 -0400 Subject: [PATCH 17/22] Changed popup menu style --- AndroidManifest.xml | 1 + res/values/reader_styles.xml | 4 +++- .../wordpress/android/ui/reader/ReaderPostListFragment.java | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 09d09e3e95d7..a14559915c40 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -168,6 +168,7 @@ -