From 06a692130ca321796df0429b6eb54e72ed694424 Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Mon, 3 Sep 2018 00:05:42 +0800 Subject: Replace the RecyclerView for comments to MultiLevelRecyclerView in order to display the comment trees easily. Click the expand more button to expand the comment tree. Click the expand less button to hide the comment tree. Rewrite some code. --- .idea/caches/build_file_checksums.ser | Bin 533 -> 533 bytes app/build.gradle | 1 + .../infinityforreddit/CommentData.java | 18 +- .../CommentMultiLevelRecyclerViewAdapter.java | 272 +++++++++++++++++++++ .../CommentRecyclerViewAdapter.java | 195 --------------- .../infinityforreddit/FetchComment.java | 5 +- .../infinityforreddit/ParseComment.java | 29 ++- .../infinityforreddit/RedditAPI.java | 3 +- .../infinityforreddit/ViewPostDetailActivity.java | 23 +- .../res/drawable/ic_arrow_downward_black_12dp.xml | 4 - .../res/drawable/ic_arrow_downward_black_20dp.xml | 4 + .../res/drawable/ic_arrow_upward_black_12dp.xml | 4 - .../res/drawable/ic_arrow_upward_black_20dp.xml | 4 + .../res/drawable/ic_expand_less_black_20dp.xml | 4 + .../res/drawable/ic_expand_more_black_20dp.xml | 4 + app/src/main/res/drawable/ic_reply_black_12dp.xml | 4 - app/src/main/res/drawable/ic_reply_black_20dp.xml | 4 + .../main/res/layout/activity_view_post_detail.xml | 7 +- app/src/main/res/layout/item_post_comment.xml | 198 ++++++++------- 19 files changed, 465 insertions(+), 318 deletions(-) create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java delete mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java delete mode 100644 app/src/main/res/drawable/ic_arrow_downward_black_12dp.xml create mode 100644 app/src/main/res/drawable/ic_arrow_downward_black_20dp.xml delete mode 100644 app/src/main/res/drawable/ic_arrow_upward_black_12dp.xml create mode 100644 app/src/main/res/drawable/ic_arrow_upward_black_20dp.xml create mode 100644 app/src/main/res/drawable/ic_expand_less_black_20dp.xml create mode 100644 app/src/main/res/drawable/ic_expand_more_black_20dp.xml delete mode 100644 app/src/main/res/drawable/ic_reply_black_12dp.xml create mode 100644 app/src/main/res/drawable/ic_reply_black_20dp.xml diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 121762e1..7b4aa4ac 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index b7f42671..4e9b7644 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -59,4 +59,5 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit:2.4.0' implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' implementation 'jp.wasabeef:glide-transformations:3.3.0' + implementation 'com.muditsen.multilevelrecyclerview:multilevelview:1.0.0' } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java index 02bc245d..ec8befee 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java @@ -1,6 +1,9 @@ package ml.docilealligator.infinityforreddit; -class CommentData { +import com.multilevelview.models.RecyclerViewItem; + +class CommentData extends RecyclerViewItem { + private String id; private String fullName; private String author; private String commentTime; @@ -14,9 +17,11 @@ class CommentData { private boolean hasReply; private boolean scoreHidden; - CommentData(String fullName, String author, String commentTime, String commentContent, int score, - boolean isSubmitter, String permalink, int depth, boolean collapsed, boolean hasReply, - boolean scoreHidden) { + CommentData(String id, String fullName, String author, String commentTime, String commentContent, + int score, boolean isSubmitter, String permalink, int depth, boolean collapsed, + boolean hasReply, boolean scoreHidden) { + super(depth); + this.id = id; this.fullName = fullName; this.author = author; this.commentTime = commentTime; @@ -30,6 +35,9 @@ class CommentData { this.scoreHidden = scoreHidden; } + public String getId() { + return id; + } public String getFullName() { return fullName; @@ -71,7 +79,7 @@ class CommentData { return collapsed; } - public boolean isHasReply() { + public boolean hasReply() { return hasReply; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java new file mode 100644 index 00000000..ce241a4c --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java @@ -0,0 +1,272 @@ +package ml.docilealligator.infinityforreddit; + +import android.content.Context; +import android.graphics.ColorFilter; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.multilevelview.MultiLevelAdapter; +import com.multilevelview.MultiLevelRecyclerView; +import com.multilevelview.models.RecyclerViewItem; + +import org.sufficientlysecure.htmltextview.HtmlTextView; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { + private Context mContext; + private ArrayList mCommentData; + private MultiLevelRecyclerView mMultiLevelRecyclerView; + private String subredditNamePrefixed; + private String article; + private Locale locale; + + CommentMultiLevelRecyclerViewAdapter(Context context, ArrayList commentData, + MultiLevelRecyclerView multiLevelRecyclerView, + String subredditNamePrefixed, String article, Locale locale) { + super(commentData); + mContext = context; + mCommentData = commentData; + mMultiLevelRecyclerView = multiLevelRecyclerView; + this.subredditNamePrefixed = subredditNamePrefixed; + this.article = article; + this.locale = locale; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_comment, parent, false)); + } + + @Override + public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { + final CommentData commentItem = mCommentData.get(position); + + ((CommentViewHolder) holder).authorTextView.setText(commentItem.getAuthor()); + ((CommentViewHolder) holder).commentTimeTextView.setText(commentItem.getCommentTime()); + ((CommentViewHolder) holder).commentHtmlTextView.setHtml(commentItem.getCommentContent()); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); + + ((CommentViewHolder) holder).verticalBlock.getLayoutParams().width = commentItem.getDepth() * 16; + if(commentItem.hasReply()) { + setExpandButton(((CommentViewHolder) holder).expandButton, commentItem.isExpanded()); + } + + ((CommentViewHolder) holder).expandButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if(commentItem.hasChildren() && commentItem.getChildren().size() > 0) { + setExpandButton(((CommentViewHolder) holder).expandButton, commentItem.isExpanded()); + mMultiLevelRecyclerView.toggleItemsGroup(holder.getAdapterPosition()); + } else { + ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.VISIBLE); + FetchComment.fetchComment(subredditNamePrefixed, article, commentItem.getId(), + new FetchComment.FetchCommentListener() { + @Override + public void onFetchCommentSuccess(String response) { + ParseComment.parseComment(response, new ArrayList(), + locale, false, commentItem.getDepth(), new ParseComment.ParseCommentListener() { + @Override + public void onParseCommentSuccess(List commentData, int moreCommentCount) { + commentItem.addChildren((List) commentData); + ((CommentViewHolder) holder).loadMoreCommentsProgressBar + .setVisibility(View.GONE); + mMultiLevelRecyclerView.toggleItemsGroup(holder.getAdapterPosition()); + } + + @Override + public void onParseCommentFail() { + ((CommentViewHolder) holder).loadMoreCommentsProgressBar + .setVisibility(View.GONE); + } + }); + } + + @Override + public void onFetchCommentFail() { + + } + }); + } + } + }); + + switch (commentItem.getVoteType()) { + case 1: + ((CommentViewHolder) holder).upvoteButton + .setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + break; + case 2: + ((CommentViewHolder) holder).downvoteButton + .setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + break; + } + + ((CommentViewHolder) holder).upvoteButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + final boolean isDownvotedBefore = ((CommentViewHolder) holder).downvoteButton.getColorFilter() != null; + final ColorFilter minusButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + + if (((CommentViewHolder) holder).upvoteButton.getColorFilter() == null) { + ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + if(isDownvotedBefore) { + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 2)); + } else { + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); + } + + VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position) { + commentItem.setVoteType(1); + if(isDownvotedBefore) { + commentItem.setScore(commentItem.getScore() + 2); + } else { + commentItem.setScore(commentItem.getScore() + 1); + } + } + + @Override + public void onVoteThingFail(int position) { + Toast.makeText(mContext, "Cannot upvote this comment", Toast.LENGTH_SHORT).show(); + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); + ((CommentViewHolder) holder).downvoteButton.setColorFilter(minusButtonColorFilter); + } + }, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); + } else { + //Upvoted before + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); + + VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position) { + commentItem.setVoteType(0); + commentItem.setScore(commentItem.getScore() - 1); + } + + @Override + public void onVoteThingFail(int position) { + Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); + ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + commentItem.setScore(commentItem.getScore() + 1); + } + }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); + } + } + }); + + ((CommentViewHolder) holder).downvoteButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + final boolean isUpvotedBefore = ((CommentViewHolder) holder).upvoteButton.getColorFilter() != null; + + final ColorFilter upvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + + if (((CommentViewHolder) holder).downvoteButton.getColorFilter() == null) { + ((CommentViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + if (isUpvotedBefore) { + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 2)); + } else { + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1)); + } + + VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position) { + commentItem.setVoteType(-1); + if(isUpvotedBefore) { + commentItem.setScore(commentItem.getScore() - 2); + } else { + commentItem.setScore(commentItem.getScore() - 1); + } + } + + @Override + public void onVoteThingFail(int position) { + Toast.makeText(mContext, "Cannot downvote this comment", Toast.LENGTH_SHORT).show(); + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); + ((CommentViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); + } + }, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition(), 1); + } else { + //Down voted before + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1)); + + VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position) { + commentItem.setVoteType(0); + commentItem.setScore(commentItem.getScore()); + } + + @Override + public void onVoteThingFail(int position) { + Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show(); + ((CommentViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); + commentItem.setScore(commentItem.getScore()); + } + }, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition(), 1); + } + } + }); + } + + @Override + public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { + ((CommentViewHolder) holder).expandButton.setVisibility(View.GONE); + ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.GONE); + } + + private void setExpandButton(ImageView expandButton, boolean isExpanded) { + // set the icon based on the current state + expandButton.setVisibility(View.VISIBLE); + expandButton.setImageResource(isExpanded ? R.drawable.ic_expand_less_black_20dp : R.drawable.ic_expand_more_black_20dp); + } + + private class CommentViewHolder extends RecyclerView.ViewHolder { + private TextView authorTextView; + private TextView commentTimeTextView; + private HtmlTextView commentHtmlTextView; + private ImageView upvoteButton; + private ImageView downvoteButton; + private TextView scoreTextView; + private ImageView expandButton; + private ProgressBar loadMoreCommentsProgressBar; + private ImageView replyButton; + private View verticalBlock; + + public CommentViewHolder(View itemView) { + super(itemView); + authorTextView = itemView.findViewById(R.id.author_text_view_item_post_comment); + commentTimeTextView = itemView.findViewById(R.id.comment_time_text_view_item_post_comment); + commentHtmlTextView = itemView.findViewById(R.id.comment_html_text_view_item_post_comment); + upvoteButton = itemView.findViewById(R.id.plus_button_item_post_comment); + downvoteButton = itemView.findViewById(R.id.minus_button_item_post_comment); + scoreTextView = itemView.findViewById(R.id.score_text_view_item_post_comment); + loadMoreCommentsProgressBar = itemView.findViewById(R.id.load_more_comments_progress_bar); + expandButton = itemView.findViewById(R.id.expand_button_item_post_comment); + replyButton = itemView.findViewById(R.id.reply_button_item_post_comment); + verticalBlock = itemView.findViewById(R.id.vertical_block_item_post_comment); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java deleted file mode 100644 index 5d876dc7..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java +++ /dev/null @@ -1,195 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.content.Context; -import android.graphics.ColorFilter; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import org.sufficientlysecure.htmltextview.HtmlTextView; - -import java.util.ArrayList; - -class CommentRecyclerViewAdapter extends RecyclerView.Adapter { - private Context mContext; - private ArrayList mCommentData; - - CommentRecyclerViewAdapter(Context context, ArrayList commentData) { - mContext = context; - mCommentData = commentData; - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_comment, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { - ((CommentViewHolder) holder).authorTextView.setText(mCommentData.get(position).getAuthor()); - ((CommentViewHolder) holder).commentTimeTextView.setText(mCommentData.get(position).getCommentTime()); - ((CommentViewHolder) holder).commentHtmlTextView.setHtml(mCommentData.get(position).getCommentContent()); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore())); - - switch (mCommentData.get(position).getVoteType()) { - case 1: - ((CommentViewHolder) holder).upvoteButton - .setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - break; - case 2: - ((CommentViewHolder) holder).downvoteButton - .setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - break; - } - - ((CommentViewHolder) holder).upvoteButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - final boolean isDownvotedBefore = ((CommentViewHolder) holder).downvoteButton.getColorFilter() != null; - final ColorFilter minusButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - - if (((CommentViewHolder) holder).upvoteButton.getColorFilter() == null) { - ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - if(isDownvotedBefore) { - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() + 2)); - } else { - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() + 1)); - } - - VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position) { - mCommentData.get(position).setVoteType(1); - if(isDownvotedBefore) { - mCommentData.get(position).setScore(mCommentData.get(position).getScore() + 2); - } else { - mCommentData.get(position).setScore(mCommentData.get(position).getScore() + 1); - } - } - - @Override - public void onVoteThingFail(int position) { - Toast.makeText(mContext, "Cannot upvote this comment", Toast.LENGTH_SHORT).show(); - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore())); - ((CommentViewHolder) holder).downvoteButton.setColorFilter(minusButtonColorFilter); - } - }, mCommentData.get(position).getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); - } else { - //Upvoted before - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() - 1)); - - VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position) { - mCommentData.get(position).setVoteType(0); - mCommentData.get(position).setScore(mCommentData.get(position).getScore() - 1); - } - - @Override - public void onVoteThingFail(int position) { - Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() + 1)); - ((CommentViewHolder) holder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - mCommentData.get(position).setScore(mCommentData.get(position).getScore() + 1); - } - }, mCommentData.get(position).getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) holder).getAdapterPosition(), 1); - } - } - }); - - ((CommentViewHolder) holder).downvoteButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - final boolean isUpvotedBefore = ((CommentViewHolder) holder).upvoteButton.getColorFilter() != null; - - final ColorFilter upvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - - if (((CommentViewHolder) holder).downvoteButton.getColorFilter() == null) { - ((CommentViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - if (isUpvotedBefore) { - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() - 2)); - } else { - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() - 1)); - } - - VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position) { - mCommentData.get(position).setVoteType(-1); - if(isUpvotedBefore) { - mCommentData.get(position).setScore(mCommentData.get(position).getScore() - 2); - } else { - mCommentData.get(position).setScore(mCommentData.get(position).getScore() - 1); - } - } - - @Override - public void onVoteThingFail(int position) { - Toast.makeText(mContext, "Cannot downvote this comment", Toast.LENGTH_SHORT).show(); - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore())); - ((CommentViewHolder) holder).upvoteButton.setColorFilter(upvoteButtonColorFilter); - } - }, mCommentData.get(position).getFullName(), RedditUtils.DIR_DOWNVOTE, holder.getAdapterPosition(), 1); - } else { - //Down voted before - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore() + 1)); - - VoteThing.voteThing(mContext, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position) { - mCommentData.get(position).setVoteType(0); - mCommentData.get(position).setScore(mCommentData.get(position).getScore()); - } - - @Override - public void onVoteThingFail(int position) { - Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show(); - ((CommentViewHolder) holder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(mCommentData.get(position).getScore())); - mCommentData.get(position).setScore(mCommentData.get(position).getScore()); - } - }, mCommentData.get(position).getFullName(), RedditUtils.DIR_UNVOTE, holder.getAdapterPosition(), 1); - } - } - }); - } - - @Override - public int getItemCount() { - return mCommentData.size(); - } - - private class CommentViewHolder extends RecyclerView.ViewHolder { - private TextView authorTextView; - private TextView commentTimeTextView; - private HtmlTextView commentHtmlTextView; - private ImageView upvoteButton; - private ImageView downvoteButton; - private TextView scoreTextView; - private ImageView replyButton; - - public CommentViewHolder(View itemView) { - super(itemView); - authorTextView = itemView.findViewById(R.id.author_text_view_item_post_comment); - commentTimeTextView = itemView.findViewById(R.id.comment_time_text_view_item_post_comment); - commentHtmlTextView = itemView.findViewById(R.id.comment_html_text_view_item_post_comment); - upvoteButton = itemView.findViewById(R.id.plus_button_item_post_comment); - downvoteButton = itemView.findViewById(R.id.minus_button_item_post_comment); - scoreTextView = itemView.findViewById(R.id.score_text_view_item_post_comment); - replyButton = itemView.findViewById(R.id.reply_button_item_post_comment); - } - } -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java index eb98a605..e4b78d78 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java @@ -15,7 +15,8 @@ class FetchComment { void onFetchCommentFail(); } - static void queryComment(String subredditNamePrefixed, String article, final FetchCommentListener fetchCommentListener) { + static void fetchComment(String subredditNamePrefixed, String article, String comment, + final FetchCommentListener fetchCommentListener) { Retrofit retrofit = new Retrofit.Builder() .baseUrl(RedditUtils.API_BASE_URI) .addConverterFactory(ScalarsConverterFactory.create()) @@ -23,7 +24,7 @@ class FetchComment { RedditAPI api = retrofit.create(RedditAPI.class); - Call comments = api.getComments(subredditNamePrefixed, article); + Call comments = api.getComments(subredditNamePrefixed, article, comment); comments.enqueue(new Callback() { @Override public void onResponse(@NonNull Call call, @NonNull Response response) { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java index 28355a04..ff87536c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java @@ -10,16 +10,18 @@ import org.json.JSONObject; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.List; import java.util.Locale; class ParseComment { interface ParseCommentListener { - void onParseCommentSuccess(ArrayList commentData, int moreCommentCount); + void onParseCommentSuccess(List commentData, int moreCommentCount); void onParseCommentFail(); } - static void parseComment(String response, ArrayList commentData, Locale locale, ParseCommentListener parseCommentListener) { - new ParseCommentAsyncTask(response, commentData, locale, parseCommentListener).execute(); + static void parseComment(String response, ArrayList commentData, Locale locale, + boolean isPost, int parentDepth, ParseCommentListener parseCommentListener) { + new ParseCommentAsyncTask(response, commentData, locale, isPost, parentDepth, parseCommentListener).execute(); } private static class ParseCommentAsyncTask extends AsyncTask { @@ -27,16 +29,21 @@ class ParseComment { private ArrayList commentData; private ArrayList newcommentData; private Locale locale; + private boolean isPost; + private int parentDepth; private ParseCommentListener parseCommentListener; private boolean parseFailed; private int moreCommentCount; - ParseCommentAsyncTask(String response, ArrayList commentData, Locale locale, ParseCommentListener parseCommentListener){ + ParseCommentAsyncTask(String response, ArrayList commentData, Locale locale, + boolean isPost, int parentDepth, ParseCommentListener parseCommentListener){ try { jsonResponse = new JSONArray(response); this.commentData = commentData; newcommentData = new ArrayList<>(); this.locale = locale; + this.isPost = isPost; + this.parentDepth = parentDepth; this.parseCommentListener = parseCommentListener; parseFailed = false; } catch (JSONException e) { @@ -50,8 +57,15 @@ class ParseComment { try { moreCommentCount = 0; int actualCommentLength; + JSONArray allComments; - JSONArray allComments = jsonResponse.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); + if(isPost) { + allComments = jsonResponse.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); + } else { + allComments = jsonResponse.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY) + .getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONObject(JSONUtils.REPLIES_KEY) + .getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); + } if(allComments.length() == 0) { return null; } @@ -68,6 +82,7 @@ class ParseComment { for (int i = 0; i < actualCommentLength; i++) { JSONObject data = allComments.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY); + String id = data.getString(JSONUtils.ID_KEY); String fullName = data.getString(JSONUtils.LINK_ID_KEY); String author = data.getString(JSONUtils.AUTHOR_KEY); boolean isSubmitter = data.getBoolean(JSONUtils.IS_SUBMITTER_KEY); @@ -85,11 +100,11 @@ class ParseComment { String formattedSubmitTime = new SimpleDateFormat("MMM d, YYYY, HH:mm", locale).format(submitTimeCalendar.getTime()); - int depth = data.getInt(JSONUtils.DEPTH_KEY); + int depth = data.getInt(JSONUtils.DEPTH_KEY) + parentDepth; boolean collapsed = data.getBoolean(JSONUtils.COLLAPSED_KEY); boolean hasReply = !(data.get(JSONUtils.REPLIES_KEY) instanceof String); - newcommentData.add(new CommentData(fullName, author, formattedSubmitTime, commentContent, score, isSubmitter, permalink, depth, collapsed, hasReply, scoreHidden)); + newcommentData.add(new CommentData(id, fullName, author, formattedSubmitTime, commentContent, score, isSubmitter, permalink, depth, collapsed, hasReply, scoreHidden)); } } catch (JSONException e) { parseFailed = true; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java index 20df642c..7b29693c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java @@ -17,7 +17,8 @@ public interface RedditAPI { Call getAccessToken(@HeaderMap Map headers, @FieldMap Map params); @GET("{subredditNamePrefixed}/comments/{article}.json?raw_json=1") - Call getComments(@Path("subredditNamePrefixed") String subredditNamePrefixed, @Path("article") String article); + Call getComments(@Path("subredditNamePrefixed") String subredditNamePrefixed, + @Path("article") String article, @Query("comment") String comment); @GET("r/{subredditName}/about.json?raw_json=1") Call getSubredditData(@Path("subredditName") String subredditName); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index f922a0d6..22950bc5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -14,7 +14,6 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.CardView; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; @@ -31,10 +30,12 @@ import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; +import com.multilevelview.MultiLevelRecyclerView; import org.sufficientlysecure.htmltextview.HtmlTextView; import java.util.ArrayList; +import java.util.List; import de.hdodenhof.circleimageview.CircleImageView; import jp.wasabeef.glide.transformations.BlurTransformation; @@ -53,7 +54,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { private CoordinatorLayout mCoordinatorLayout; private ProgressBar mCommentProgressbar; private CardView mCommentCardView; - private RecyclerView mRecyclerView; + private MultiLevelRecyclerView mRecyclerView; private LinearLayout mNoCommentWrapperLinearLayout; private ImageView mNoCommentImageView; @@ -454,19 +455,25 @@ public class ViewPostDetailActivity extends AppCompatActivity { private void queryComment() { mCommentProgressbar.setVisibility(View.VISIBLE); mNoCommentWrapperLinearLayout.setVisibility(View.GONE); - FetchComment.queryComment(mPostData.getSubredditNamePrefixed(), mPostData.getId(), - new FetchComment.FetchCommentListener() { + FetchComment.fetchComment(mPostData.getSubredditNamePrefixed(), mPostData.getId(), + null, new FetchComment.FetchCommentListener() { @Override public void onFetchCommentSuccess(String response) { ParseComment.parseComment(response, new ArrayList(), - getResources().getConfiguration().locale, new ParseComment.ParseCommentListener() { + getResources().getConfiguration().locale, true, 0, + new ParseComment.ParseCommentListener() { @Override - public void onParseCommentSuccess(ArrayList commentData, int moreCommentCount) { + public void onParseCommentSuccess(List commentData, int moreCommentCount) { mCommentProgressbar.setVisibility(View.GONE); mMoreCommentCount = moreCommentCount; if (commentData.size() > 0) { - CommentRecyclerViewAdapter adapter = new CommentRecyclerViewAdapter( - ViewPostDetailActivity.this, commentData); + CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter( + ViewPostDetailActivity.this, (ArrayList) commentData, + mRecyclerView, mPostData.getSubredditNamePrefixed(), + mPostData.getId(), getResources().getConfiguration().locale); + mRecyclerView.removeItemClickListeners(); + mRecyclerView.setToggleItemOnClick(false); + mRecyclerView.setAccordion(false); mRecyclerView.setAdapter(adapter); mCommentCardView.setVisibility(View.VISIBLE); } else { diff --git a/app/src/main/res/drawable/ic_arrow_downward_black_12dp.xml b/app/src/main/res/drawable/ic_arrow_downward_black_12dp.xml deleted file mode 100644 index 91cbabce..00000000 --- a/app/src/main/res/drawable/ic_arrow_downward_black_12dp.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_arrow_downward_black_20dp.xml b/app/src/main/res/drawable/ic_arrow_downward_black_20dp.xml new file mode 100644 index 00000000..964c12ac --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_downward_black_20dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_arrow_upward_black_12dp.xml b/app/src/main/res/drawable/ic_arrow_upward_black_12dp.xml deleted file mode 100644 index 355c40f0..00000000 --- a/app/src/main/res/drawable/ic_arrow_upward_black_12dp.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_arrow_upward_black_20dp.xml b/app/src/main/res/drawable/ic_arrow_upward_black_20dp.xml new file mode 100644 index 00000000..320c0fc8 --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_upward_black_20dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_less_black_20dp.xml b/app/src/main/res/drawable/ic_expand_less_black_20dp.xml new file mode 100644 index 00000000..54ce5912 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_less_black_20dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_more_black_20dp.xml b/app/src/main/res/drawable/ic_expand_more_black_20dp.xml new file mode 100644 index 00000000..2e1e234a --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_more_black_20dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_reply_black_12dp.xml b/app/src/main/res/drawable/ic_reply_black_12dp.xml deleted file mode 100644 index e35610aa..00000000 --- a/app/src/main/res/drawable/ic_reply_black_12dp.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_reply_black_20dp.xml b/app/src/main/res/drawable/ic_reply_black_20dp.xml new file mode 100644 index 00000000..9cb7e46c --- /dev/null +++ b/app/src/main/res/drawable/ic_reply_black_20dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/layout/activity_view_post_detail.xml b/app/src/main/res/layout/activity_view_post_detail.xml index 4e9feffc..c3a1c688 100644 --- a/app/src/main/res/layout/activity_view_post_detail.xml +++ b/app/src/main/res/layout/activity_view_post_detail.xml @@ -258,7 +258,12 @@ android:textColor="#000000" android:textSize="18sp" /> - --> + + diff --git a/app/src/main/res/layout/item_post_comment.xml b/app/src/main/res/layout/item_post_comment.xml index c1421084..6981b955 100644 --- a/app/src/main/res/layout/item_post_comment.xml +++ b/app/src/main/res/layout/item_post_comment.xml @@ -2,104 +2,128 @@ + android:id="@+id/linear_layout_item_post_comment"> + + + android:layout_height="wrap_content" + android:layout_marginTop="12dp" + android:layout_marginBottom="12dp" + android:orientation="vertical"> - + android:layout_marginEnd="16dp"> - + - + - - - - - - - + - - - + + - - + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp"> + + + + + + + + + + + + + + + + \ No newline at end of file -- cgit v1.2.3