package org.wordpress.android.ui.reader.views; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.LinearLayout; import android.widget.TextView; import org.wordpress.android.R; import org.wordpress.android.ui.reader.actions.ReaderActions; import org.wordpress.android.ui.reader.actions.ReaderBlogActions; import org.wordpress.android.ui.reader.models.ReaderRelatedPost; import org.wordpress.android.ui.reader.models.ReaderRelatedPostList; import org.wordpress.android.util.AnalyticsUtils; import org.wordpress.android.util.DisplayUtils; import org.wordpress.android.util.GravatarUtils; import org.wordpress.android.util.NetworkUtils; import org.wordpress.android.util.PhotonUtils; import org.wordpress.android.util.ToastUtils; import org.wordpress.android.widgets.WPNetworkImageView; /** * used by the detail view to display related posts, which can be either local (related posts * from the same site as the source post) or global (related posts from across wp.com) */ public class ReaderRelatedPostsView extends LinearLayout { public interface OnRelatedPostClickListener { void onRelatedPostClick(View v, long siteId, long postId); } private OnRelatedPostClickListener mClickListener; private int mFeaturedImageWidth; private final ReaderRelatedPostList mRelatedPostList = new ReaderRelatedPostList(); public ReaderRelatedPostsView(Context context) { super(context); initView(context); } public ReaderRelatedPostsView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public ReaderRelatedPostsView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public ReaderRelatedPostsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initView(context); } private void initView(Context context) { inflate(context, R.layout.reader_related_posts_view, this); mFeaturedImageWidth = DisplayUtils.dpToPx(context, context.getResources().getDimensionPixelSize(R.dimen.reader_related_post_image_width)); } public void setOnRelatedPostClickListener(OnRelatedPostClickListener listener) { mClickListener = listener; } public void showRelatedPosts(@NonNull ReaderRelatedPostList posts, String siteName, boolean isGlobal) { mRelatedPostList.clear(); mRelatedPostList.addAll(posts); ViewGroup container = (ViewGroup) findViewById(R.id.container_related_posts); container.removeAllViews(); // nothing more to do if passed list is empty if (mRelatedPostList.size() == 0) return; int avatarSize = DisplayUtils.dpToPx(getContext(), getResources().getDimensionPixelSize(R.dimen.avatar_sz_extra_small)); // add a separate view for each related post LayoutInflater inflater = LayoutInflater.from(getContext()); for (int index = 0; index < mRelatedPostList.size(); index++) { final int position = index; ReaderRelatedPost relatedPost = mRelatedPostList.get(position); View postView = inflater.inflate(R.layout.reader_related_post, container, false); TextView txtTitle = (TextView) postView.findViewById(R.id.text_related_post_title); TextView txtExcerpt = (TextView) postView.findViewById(R.id.text_related_post_excerpt); View siteHeader = postView.findViewById(R.id.layout_related_post_site_header); txtTitle.setText(relatedPost.getTitle()); if (relatedPost.hasExcerpt()) { txtExcerpt.setText(relatedPost.getExcerpt()); txtExcerpt.setVisibility(View.VISIBLE); } else { txtExcerpt.setVisibility(View.GONE); } // site header only appears for global related posts if (isGlobal) { WPNetworkImageView imgAvatar = (WPNetworkImageView) siteHeader.findViewById(R.id.image_avatar); TextView txtSiteName = (TextView) siteHeader.findViewById(R.id.text_site_name); TextView txtAuthorName = (TextView) siteHeader.findViewById(R.id.text_author_name); txtSiteName.setText(relatedPost.getSiteName()); txtAuthorName.setText(relatedPost.getAuthorName()); if (relatedPost.hasAuthorAvatarUrl()) { imgAvatar.setVisibility(View.VISIBLE); String avatarUrl = GravatarUtils.fixGravatarUrl(relatedPost.getAuthorAvatarUrl(), avatarSize); imgAvatar.setImageUrl(avatarUrl, WPNetworkImageView.ImageType.AVATAR); } else { imgAvatar.setVisibility(View.GONE); } final ReaderFollowButton btnFollow = (ReaderFollowButton) siteHeader.findViewById(R.id.related_post_follow_button); btnFollow.setIsFollowed(relatedPost.isFollowing()); btnFollow.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { toggleFollowStatus(btnFollow, position); } }); siteHeader.setVisibility(View.VISIBLE); } else { siteHeader.setVisibility(View.GONE); } showFeaturedImage(postView, relatedPost); postView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mClickListener != null) { mClickListener.onRelatedPostClick(view, mRelatedPostList.get(position).getSiteId(), mRelatedPostList.get(position).getPostId()); } } }); container.addView(postView); } // make sure the label for these related posts has the correct caption TextView label = (TextView) findViewById(R.id.text_related_posts_label); if (isGlobal) { label.setText(getContext().getString(R.string.reader_label_global_related_posts)); } else { label.setText(String.format(getContext().getString(R.string.reader_label_local_related_posts), siteName)); } } /** * user tapped follow button on a global related post * @param btnFollow Follow button for the site to follow * @param position index of the related post in mRelatedPosts */ private void toggleFollowStatus(final ReaderFollowButton btnFollow, final int position) { if (!NetworkUtils.checkConnection(getContext())) return; final boolean isAskingToFollow = !mRelatedPostList.get(position).isFollowing(); ReaderActions.ActionListener listener = new ReaderActions.ActionListener() { @Override public void onActionResult(boolean succeeded) { if (getContext() == null) return; btnFollow.setEnabled(true); if (succeeded) { mRelatedPostList.get(position).setIsFollowing(isAskingToFollow); } else { int errResId = isAskingToFollow ? R.string.reader_toast_err_follow_blog : R.string.reader_toast_err_unfollow_blog; ToastUtils.showToast(getContext(), errResId); btnFollow.setIsFollowed(!isAskingToFollow); } } }; // disable follow button until call completes btnFollow.setEnabled(false); ReaderBlogActions.followBlogById(mRelatedPostList.get(position).getSiteId(), isAskingToFollow, listener); btnFollow.setIsFollowedAnimated(isAskingToFollow); } /** * shows the featured image for the passed related post, if available * @param postView parent view which contains the featured image and other related post views * @param relatedPost related post to operate on */ private void showFeaturedImage(final View postView, final ReaderRelatedPost relatedPost) { final WPNetworkImageView imgFeatured = (WPNetworkImageView) postView.findViewById(R.id.image_featured); // post must have an excerpt in order to show featured image (not enough space otherwise) if (!relatedPost.hasFeaturedImageUrl() || !relatedPost.hasExcerpt()) { imgFeatured.setVisibility(View.GONE); return; } // featured image has height set to MATCH_PARENT so wait for parent view's layout to complete // before loading image so we can set the image height correctly, then tell the imageView // to crop the downloaded image to fit the exact width/height of the view postView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { postView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int cropWidth = mFeaturedImageWidth; int cropHeight = postView.getHeight(); String photonUrl = PhotonUtils.getPhotonImageUrl( relatedPost.getFeaturedImageUrl(), cropWidth, cropHeight); imgFeatured.setImageUrl( photonUrl, WPNetworkImageView.ImageType.PHOTO, null, cropWidth, cropHeight); } }); imgFeatured.setVisibility(View.VISIBLE); } /* * called by reader detail when this related posts view is scrolled into view, tracks * railcar events for each related post */ public void trackRailcarRender() { for (ReaderRelatedPost post: mRelatedPostList) { AnalyticsUtils.trackRailcarRender(post.getRailcarJson()); } } }