From 25f2a35d227b299ff202969f614eab914bf8f6ec Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Tue, 18 Jun 2019 00:01:15 +0800 Subject: Reimplemented parsing comments using recursion to parse all the child comments. Reimplemented CommentRecyclerView (some methods need proper implementation. Minor bugs fixed. --- .idea/caches/build_file_checksums.ser | Bin 533 -> 533 bytes .idea/caches/gradle_models.ser | Bin 253985 -> 251125 bytes app/build.gradle | 1 - .../infinityforreddit/CommentActivity.java | 2 - .../infinityforreddit/CommentData.java | 232 ++++++++++++- .../CommentMultiLevelRecyclerViewAdapter.java | 322 ----------------- .../CommentRecyclerViewAdapter.java | 379 +++++++++++++++++++++ .../infinityforreddit/FetchComment.java | 21 +- .../infinityforreddit/ParseComment.java | 99 +++--- .../infinityforreddit/ViewPostDetailActivity.java | 28 +- .../main/res/layout/activity_view_post_detail.xml | 7 +- app/src/main/res/layout/item_comment.xml | 1 + 12 files changed, 694 insertions(+), 398 deletions(-) delete mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 2c42422d..493bc715 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser index a44d1840..4b82c52a 100644 Binary files a/.idea/caches/gradle_models.ser and b/.idea/caches/gradle_models.ser differ diff --git a/app/build.gradle b/app/build.gradle index 4a6323e5..bf88d288 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -61,7 +61,6 @@ dependencies { implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' implementation 'jp.wasabeef:glide-transformations:4.0.0' - implementation 'com.muditsen.multilevelrecyclerview:multilevelview:1.0.0' implementation 'com.google.dagger:dagger:2.17' annotationProcessor 'com.google.dagger:dagger-compiler:2.17' implementation 'com.jakewharton:butterknife:10.1.0' diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentActivity.java index 9bf4ebc7..eef1d810 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentActivity.java @@ -3,7 +3,6 @@ package ml.docilealligator.infinityforreddit; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; @@ -70,7 +69,6 @@ public class CommentActivity extends AppCompatActivity { toolbar.setTitle(getString(R.string.comment_activity_label_is_replying)); } - Log.i("fullname", parentFullname); setSupportActionBar(toolbar); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java index 57e95bae..043c0071 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java @@ -3,14 +3,15 @@ package ml.docilealligator.infinityforreddit; import android.os.Parcel; import android.os.Parcelable; -import com.multilevelview.models.RecyclerViewItem; +import java.util.ArrayList; -class CommentData extends RecyclerViewItem implements Parcelable { +class CommentData implements Parcelable { private String id; private String fullName; private String author; private String commentTime; private String commentContent; + private String parentId; private int score; private int voteType; private boolean isSubmitter; @@ -19,16 +20,217 @@ class CommentData extends RecyclerViewItem implements Parcelable { private boolean collapsed; private boolean hasReply; private boolean scoreHidden; + private boolean isExpanded; + private ArrayList children; + private ArrayList moreChildrenIds; 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) { + String parentId, int score, boolean isSubmitter, String permalink, int depth, + boolean collapsed, boolean hasReply, boolean scoreHidden) { + this.id = id; + this.fullName = fullName; + this.author = author; + this.commentTime = commentTime; + this.commentContent = commentContent; + this.parentId = parentId; + this.score = score; + this.isSubmitter = isSubmitter; + this.permalink = RedditUtils.API_BASE_URI + permalink; + this.depth = depth; + this.collapsed = collapsed; + this.hasReply = hasReply; + this.scoreHidden = scoreHidden; + this.isExpanded = false; + } + + protected CommentData(Parcel in) { + id = in.readString(); + fullName = in.readString(); + author = in.readString(); + commentTime = in.readString(); + commentContent = in.readString(); + parentId = in.readString(); + score = in.readInt(); + voteType = in.readInt(); + isSubmitter = in.readByte() != 0; + permalink = in.readString(); + depth = in.readInt(); + collapsed = in.readByte() != 0; + hasReply = in.readByte() != 0; + scoreHidden = in.readByte() != 0; + isExpanded = in.readByte() != 0; + in.readStringList(moreChildrenIds); + } + + public static final Creator CREATOR = new Creator() { + @Override + public CommentData createFromParcel(Parcel in) { + return new CommentData(in); + } + + @Override + public CommentData[] newArray(int size) { + return new CommentData[size]; + } + }; + + public String getId() { + return id; + } + + public String getFullName() { + return fullName; + } + + public String getAuthor() { + return author; + } + + public String getCommentTime() { + return commentTime; + } + + public String getCommentContent() { + return commentContent; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + public boolean isSubmitter() { + return isSubmitter; + } + + public String getPermalink() { + return permalink; + } + + public int getDepth() { + return depth; + } + + public boolean isCollapsed() { + return collapsed; + } + + public boolean hasReply() { + return hasReply; + } + + public void setHasReply(boolean hasReply) { + this.hasReply = hasReply; + } + + public boolean isScoreHidden() { + return scoreHidden; + } + + public boolean isExpanded() { + return isExpanded; + } + + public void setExpanded(boolean isExpanded) { + this.isExpanded = isExpanded; + } + + public int getVoteType() { + return voteType; + } + + public void setVoteType(int voteType) { + this.voteType = voteType; + } + + public ArrayList getChildren() { + return children; + } + + public void setChildren(ArrayList children) { + this.children = children; + } + + public void addChildren(ArrayList moreChildren) { + if(children == null) { + setChildren(moreChildren); + } else { + children.addAll(moreChildren); + } + } + + public ArrayList getMoreChildrenIds() { + return moreChildrenIds; + } + + public void setMoreChildrenIds(ArrayList moreChildrenIds) { + this.moreChildrenIds = moreChildrenIds; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(id); + parcel.writeString(fullName); + parcel.writeString(author); + parcel.writeString(commentTime); + parcel.writeString(commentContent); + parcel.writeString(parentId); + parcel.writeInt(score); + parcel.writeInt(voteType); + parcel.writeByte((byte) (isSubmitter ? 1 : 0)); + parcel.writeString(permalink); + parcel.writeInt(depth); + parcel.writeByte((byte) (collapsed ? 1 : 0)); + parcel.writeByte((byte) (hasReply ? 1 : 0)); + parcel.writeByte((byte) (scoreHidden ? 1 : 0)); + parcel.writeByte((byte) (isExpanded ? 1 : 0)); + parcel.writeStringList(moreChildrenIds); + } +} + +/*class CommentData extends RecyclerViewItem implements Parcelable { + private String id; + private String fullName; + private String author; + private String commentTime; + private String commentContent; + private String parentId; + private int score; + private int voteType; + private boolean isSubmitter; + private String permalink; + private int depth; + private boolean collapsed; + private boolean hasReply; + private boolean scoreHidden; + private ArrayList moreChildrenIds; + + CommentData(String id, String fullName, String author, String commentTime, String commentContent, + String parentId, 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; this.commentContent = commentContent; + this.parentId = parentId; this.score = score; this.isSubmitter = isSubmitter; this.permalink = RedditUtils.API_BASE_URI + permalink; @@ -45,6 +247,7 @@ class CommentData extends RecyclerViewItem implements Parcelable { author = in.readString(); commentTime = in.readString(); commentContent = in.readString(); + parentId = in.readString(); score = in.readInt(); voteType = in.readInt(); isSubmitter = in.readByte() != 0; @@ -53,6 +256,7 @@ class CommentData extends RecyclerViewItem implements Parcelable { collapsed = in.readByte() != 0; hasReply = in.readByte() != 0; scoreHidden = in.readByte() != 0; + in.readStringList(moreChildrenIds); super.setLevel(depth); } @@ -88,6 +292,14 @@ class CommentData extends RecyclerViewItem implements Parcelable { return commentContent; } + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + public int getScore() { return score; } @@ -132,6 +344,14 @@ class CommentData extends RecyclerViewItem implements Parcelable { this.voteType = voteType; } + public ArrayList getMoreChildrenIds() { + return moreChildrenIds; + } + + public void setMoreChildrenIds(ArrayList moreChildrenIds) { + this.moreChildrenIds = moreChildrenIds; + } + @Override public int describeContents() { return 0; @@ -144,6 +364,7 @@ class CommentData extends RecyclerViewItem implements Parcelable { parcel.writeString(author); parcel.writeString(commentTime); parcel.writeString(commentContent); + parcel.writeString(parentId); parcel.writeInt(score); parcel.writeInt(voteType); parcel.writeByte((byte) (isSubmitter ? 1 : 0)); @@ -152,5 +373,6 @@ class CommentData extends RecyclerViewItem implements Parcelable { parcel.writeByte((byte) (collapsed ? 1 : 0)); parcel.writeByte((byte) (hasReply ? 1 : 0)); parcel.writeByte((byte) (scoreHidden ? 1 : 0)); + parcel.writeStringList(moreChildrenIds); } -} +}*/ diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java deleted file mode 100644 index 1f5795fe..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentMultiLevelRecyclerViewAdapter.java +++ /dev/null @@ -1,322 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.ColorFilter; -import android.net.Uri; -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 androidx.annotation.NonNull; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.core.content.ContextCompat; -import androidx.recyclerview.widget.RecyclerView; - -import com.multilevelview.MultiLevelAdapter; -import com.multilevelview.MultiLevelRecyclerView; -import com.multilevelview.models.RecyclerViewItem; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import butterknife.BindView; -import butterknife.ButterKnife; -import retrofit2.Retrofit; -import ru.noties.markwon.SpannableConfiguration; -import ru.noties.markwon.view.MarkwonView; - -class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter { - private Activity mActivity; - private Retrofit mRetrofit; - private Retrofit mOauthRetrofit; - private SharedPreferences mSharedPreferences; - private ArrayList mCommentData; - private MultiLevelRecyclerView mMultiLevelRecyclerView; - private String subredditNamePrefixed; - private String article; - private Locale locale; - - CommentMultiLevelRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, - SharedPreferences sharedPreferences, ArrayList commentData, - MultiLevelRecyclerView multiLevelRecyclerView, - String subredditNamePrefixed, String article, Locale locale) { - super(commentData); - mActivity = activity; - mRetrofit = retrofit; - mOauthRetrofit = oauthRetrofit; - mSharedPreferences = sharedPreferences; - 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_comment, parent, false)); - } - - @Override - public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) { - final CommentData commentItem = mCommentData.get(position); - - String authorPrefixed = "u/" + commentItem.getAuthor(); - ((CommentViewHolder) holder).authorTextView.setText(authorPrefixed); - ((CommentViewHolder) holder).authorTextView.setOnClickListener(view -> { - Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, commentItem.getAuthor()); - mActivity.startActivity(intent); - }); - - ((CommentViewHolder) holder).commentTimeTextView.setText(commentItem.getCommentTime()); - SpannableConfiguration spannableConfiguration = SpannableConfiguration.builder(mActivity).linkResolver((view, link) -> { - if (link.startsWith("/u/") || link.startsWith("u/")) { - Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3)); - mActivity.startActivity(intent); - } else if (link.startsWith("/r/") || link.startsWith("r/")) { - Intent intent = new Intent(mActivity, ViewSubredditDetailActivity.class); - intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3)); - mActivity.startActivity(intent); - } else { - CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); - // add share action to menu list - builder.addDefaultShareMenuItem(); - builder.setToolbarColor(mActivity.getResources().getColor(R.color.colorPrimary)); - CustomTabsIntent customTabsIntent = builder.build(); - customTabsIntent.launchUrl(mActivity, Uri.parse(link)); - } - }).build(); - - ((CommentViewHolder) holder).commentMarkdownView.setMarkdown(spannableConfiguration, 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).shareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - String extraText = commentItem.getPermalink(); - intent.putExtra(Intent.EXTRA_TEXT, extraText); - mActivity.startActivity(Intent.createChooser(intent, "Share")); - } - }); - - ((CommentViewHolder) holder).expandButton.setOnClickListener(view -> { - if (commentItem.hasChildren() && commentItem.getChildren().size() > 0) { - mMultiLevelRecyclerView.toggleItemsGroup(holder.getAdapterPosition()); - setExpandButton(((CommentViewHolder) holder).expandButton, commentItem.isExpanded()); - } else { - ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.VISIBLE); - FetchComment.fetchAllComment(mRetrofit, subredditNamePrefixed, article, commentItem.getId(), - locale, false, commentItem.getDepth(), new FetchComment.FetchAllCommentListener() { - @Override - public void onFetchAllCommentSuccess(List commentData) { - commentItem.addChildren((List) commentData); - ((CommentViewHolder) holder).loadMoreCommentsProgressBar - .setVisibility(View.GONE); - mMultiLevelRecyclerView.toggleItemsGroup(holder.getAdapterPosition()); - ((CommentViewHolder) holder).expandButton - .setImageResource(R.drawable.ic_expand_less_black_20dp); - } - - @Override - public void onFetchAllCommentFailed() { - ((CommentViewHolder) holder).loadMoreCommentsProgressBar - .setVisibility(View.GONE); - } - }); - } - }); - - ((CommentViewHolder) holder).replyButton.setOnClickListener(view -> { - Intent intent = new Intent(mActivity, CommentActivity.class); - intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, commentItem.getDepth() + 1); - intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, commentItem.getCommentContent()); - intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, commentItem.getFullName()); - intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true); - mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE); - }); - - switch (commentItem.getVoteType()) { - case 1: - ((CommentViewHolder) holder).upvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - break; - case 2: - ((CommentViewHolder) holder).downvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - break; - } - - ((CommentViewHolder) holder).upvoteButton.setOnClickListener(view -> { - ColorFilter previousUpvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); - ColorFilter previousDownvoteButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); - int previousVoteType = commentItem.getVoteType(); - String newVoteType; - - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - - if(previousUpvoteButtonColorFilter == null) { - //Not upvoted before - commentItem.setVoteType(1); - newVoteType = RedditUtils.DIR_UPVOTE; - ((CommentViewHolder) holder).upvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - //Upvoted before - commentItem.setVoteType(0); - newVoteType = RedditUtils.DIR_UNVOTE; - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - } - - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); - - VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position1) { - if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) { - commentItem.setVoteType(1); - ((CommentViewHolder) holder).upvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - commentItem.setVoteType(0); - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - } - - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); - } - - @Override - public void onVoteThingFail(int position1) { - Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show(); - commentItem.setVoteType(previousVoteType); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + previousVoteType)); - ((CommentViewHolder) holder).upvoteButton.setColorFilter(previousUpvoteButtonColorFilter); - ((CommentViewHolder) holder).downvoteButton.setColorFilter(previousDownvoteButtonColorFilter); - } - }, commentItem.getFullName(), newVoteType, holder.getAdapterPosition()); - }); - - ((CommentViewHolder) holder).downvoteButton.setOnClickListener(view -> { - ColorFilter previousUpvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); - ColorFilter previousDownvoteButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); - int previousVoteType = commentItem.getVoteType(); - String newVoteType; - - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - - if(previousDownvoteButtonColorFilter == null) { - //Not downvoted before - commentItem.setVoteType(-1); - newVoteType = RedditUtils.DIR_DOWNVOTE; - ((CommentViewHolder) holder).downvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - //Downvoted before - commentItem.setVoteType(0); - newVoteType = RedditUtils.DIR_UNVOTE; - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - } - - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); - - VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position1) { - if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) { - commentItem.setVoteType(-1); - ((CommentViewHolder) holder).downvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - commentItem.setVoteType(0); - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - } - - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); - } - - @Override - public void onVoteThingFail(int position1) { - Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show(); - commentItem.setVoteType(previousVoteType); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + previousVoteType)); - ((CommentViewHolder) holder).upvoteButton.setColorFilter(previousUpvoteButtonColorFilter); - ((CommentViewHolder) holder).downvoteButton.setColorFilter(previousDownvoteButtonColorFilter); - } - }, commentItem.getFullName(), newVoteType, holder.getAdapterPosition()); - }); - } - - @Override - public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { - if (holder instanceof CommentViewHolder) { - ((CommentViewHolder) holder).expandButton.setVisibility(View.GONE); - ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.GONE); - } - } - - void addComments(ArrayList comments) { - int sizeBefore = mCommentData.size(); - mCommentData.addAll(comments); - notifyItemRangeInserted(sizeBefore, mCommentData.size() - sizeBefore); - } - - void addComment(CommentData comment) { - mCommentData.add(0, comment); - notifyItemInserted(0); - } - - void addChildComment(CommentData comment, int parentPosition) { - List childComments = mCommentData.get(parentPosition).getChildren(); - if(childComments == null) { - childComments = new ArrayList<>(); - } - childComments.add(0, comment); - mCommentData.get(parentPosition).addChildren(childComments); - mCommentData.get(parentPosition).setHasReply(true); - notifyItemChanged(parentPosition); - mMultiLevelRecyclerView.toggleItemsGroup(parentPosition); - } - - 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); - } - - class CommentViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.author_text_view_item_post_comment) TextView authorTextView; - @BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView; - @BindView(R.id.comment_markdown_view_item_post_comment) MarkwonView commentMarkdownView; - @BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton; - @BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView; - @BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton; - @BindView(R.id.load_more_comments_progress_bar) ProgressBar loadMoreCommentsProgressBar; - @BindView(R.id.expand_button_item_post_comment) ImageView expandButton; - @BindView(R.id.share_button_item_post_comment) ImageView shareButton; - @BindView(R.id.reply_button_item_post_comment) ImageView replyButton; - @BindView(R.id.vertical_block_item_post_comment) View verticalBlock; - - CommentViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - } - } -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java new file mode 100644 index 00000000..e9da8bde --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java @@ -0,0 +1,379 @@ +package ml.docilealligator.infinityforreddit; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.ColorFilter; +import android.net.Uri; +import android.os.Handler; +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 androidx.annotation.NonNull; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import retrofit2.Retrofit; +import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.view.MarkwonView; + +class CommentRecyclerViewAdapter extends RecyclerView.Adapter { + private Activity mActivity; + private Retrofit mRetrofit; + private Retrofit mOauthRetrofit; + private SharedPreferences mSharedPreferences; + private ArrayList mCommentData; + private RecyclerView mRecyclerView; + private String mSubredditNamePrefixed; + private String mArticle; + private Locale mLocale; + + private ArrayList mVisibleComments; + + CommentRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, + SharedPreferences sharedPreferences, ArrayList commentData, + RecyclerView recyclerView, + String subredditNamePrefixed, String article, Locale locale) { + mActivity = activity; + mRetrofit = retrofit; + mOauthRetrofit = oauthRetrofit; + mSharedPreferences = sharedPreferences; + mCommentData = commentData; + mRecyclerView = recyclerView; + mSubredditNamePrefixed = subredditNamePrefixed; + mArticle = article; + mLocale = locale; + mVisibleComments = new ArrayList<>(); + + new Handler().post(() -> { + makeChildrenVisible(commentData, mVisibleComments); + notifyDataSetChanged(); + }); + } + + private void makeChildrenVisible(ArrayList comments, ArrayList visibleComments) { + for(CommentData c : comments) { + visibleComments.add(c); + if(c.hasReply()) { + c.setExpanded(true); + makeChildrenVisible(c.getChildren(), visibleComments); + } + } + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + final CommentData commentItem = mVisibleComments.get(position); + + String authorPrefixed = "u/" + commentItem.getAuthor(); + ((CommentViewHolder) holder).authorTextView.setText(authorPrefixed); + ((CommentViewHolder) holder).authorTextView.setOnClickListener(view -> { + Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, commentItem.getAuthor()); + mActivity.startActivity(intent); + }); + + ((CommentViewHolder) holder).commentTimeTextView.setText(commentItem.getCommentTime()); + + SpannableConfiguration spannableConfiguration = SpannableConfiguration.builder(mActivity).linkResolver((view, link) -> { + if (link.startsWith("/u/") || link.startsWith("u/")) { + Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3)); + mActivity.startActivity(intent); + } else if (link.startsWith("/r/") || link.startsWith("r/")) { + Intent intent = new Intent(mActivity, ViewSubredditDetailActivity.class); + intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3)); + mActivity.startActivity(intent); + } else { + CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); + // add share action to menu list + builder.addDefaultShareMenuItem(); + builder.setToolbarColor(mActivity.getResources().getColor(R.color.colorPrimary)); + CustomTabsIntent customTabsIntent = builder.build(); + customTabsIntent.launchUrl(mActivity, Uri.parse(link)); + } + }).build(); + + ((CommentViewHolder) holder).commentMarkdownView.setMarkdown(spannableConfiguration, commentItem.getCommentContent()); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore())); + + ((CommentViewHolder) holder).verticalBlock.getLayoutParams().width = commentItem.getDepth() * 16; + + ((CommentViewHolder) holder).shareButton.setOnClickListener(view -> { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + String extraText = commentItem.getPermalink(); + intent.putExtra(Intent.EXTRA_TEXT, extraText); + mActivity.startActivity(Intent.createChooser(intent, "Share")); + }); + + if (commentItem.hasReply()) { + if(commentItem.isExpanded()) { + ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); + } else { + ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); + } + ((CommentViewHolder) holder).expandButton.setVisibility(View.VISIBLE); + } + + ((CommentViewHolder) holder).expandButton.setOnClickListener(view -> { + if(commentItem.isExpanded()) { + collapseChildren(holder.getAdapterPosition()); + ((CommentViewHolder) holder).expandButton + .setImageResource(R.drawable.ic_expand_more_black_20dp); + } else { + expandChildren(holder.getAdapterPosition()); + commentItem.setExpanded(true); + ((CommentViewHolder) holder).expandButton + .setImageResource(R.drawable.ic_expand_less_black_20dp); + } + /*if (commentItem.hasReply() && commentItem.getChildren().size() > 0) { + collapseChildren(holder.getAdapterPosition()); + ((CommentViewHolder) holder).expandButton + .setImageResource(R.drawable.ic_expand_more_black_20dp); + } else { + ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.VISIBLE); + FetchComment.fetchAllComment(mRetrofit, mSubredditNamePrefixed, article, commentItem.getId(), + locale, false, commentItem.getDepth(), new FetchComment.FetchAllCommentListener() { + @Override + public void onFetchAllCommentSuccess(List commentData) { + commentItem.addChildren((ArrayList) commentData); + ((CommentViewHolder) holder).loadMoreCommentsProgressBar + .setVisibility(View.GONE); + expandChildren(holder.getAdapterPosition()); + ((CommentViewHolder) holder).expandButton + .setImageResource(R.drawable.ic_expand_less_black_20dp); + } + + @Override + public void onFetchAllCommentFailed() { + ((CommentViewHolder) holder).loadMoreCommentsProgressBar + .setVisibility(View.GONE); + } + }); + }*/ + }); + + ((CommentViewHolder) holder).replyButton.setOnClickListener(view -> { + Intent intent = new Intent(mActivity, CommentActivity.class); + intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, commentItem.getDepth() + 1); + intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, commentItem.getCommentContent()); + intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, commentItem.getFullName()); + intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true); + intent.putExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, holder.getAdapterPosition()); + mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE); + }); + + switch (commentItem.getVoteType()) { + case 1: + ((CommentViewHolder) holder).upvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + break; + case 2: + ((CommentViewHolder) holder).downvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + break; + } + + ((CommentViewHolder) holder).upvoteButton.setOnClickListener(view -> { + ColorFilter previousUpvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); + ColorFilter previousDownvoteButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); + int previousVoteType = commentItem.getVoteType(); + String newVoteType; + + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + + if(previousUpvoteButtonColorFilter == null) { + //Not upvoted before + commentItem.setVoteType(1); + newVoteType = RedditUtils.DIR_UPVOTE; + ((CommentViewHolder) holder).upvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + //Upvoted before + commentItem.setVoteType(0); + newVoteType = RedditUtils.DIR_UNVOTE; + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + } + + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); + + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position1) { + if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) { + commentItem.setVoteType(1); + ((CommentViewHolder) holder).upvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + commentItem.setVoteType(0); + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + } + + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); + } + + @Override + public void onVoteThingFail(int position1) { + Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show(); + commentItem.setVoteType(previousVoteType); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + previousVoteType)); + ((CommentViewHolder) holder).upvoteButton.setColorFilter(previousUpvoteButtonColorFilter); + ((CommentViewHolder) holder).downvoteButton.setColorFilter(previousDownvoteButtonColorFilter); + } + }, commentItem.getFullName(), newVoteType, holder.getAdapterPosition()); + }); + + ((CommentViewHolder) holder).downvoteButton.setOnClickListener(view -> { + ColorFilter previousUpvoteButtonColorFilter = ((CommentViewHolder) holder).upvoteButton.getColorFilter(); + ColorFilter previousDownvoteButtonColorFilter = ((CommentViewHolder) holder).downvoteButton.getColorFilter(); + int previousVoteType = commentItem.getVoteType(); + String newVoteType; + + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + + if(previousDownvoteButtonColorFilter == null) { + //Not downvoted before + commentItem.setVoteType(-1); + newVoteType = RedditUtils.DIR_DOWNVOTE; + ((CommentViewHolder) holder).downvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + //Downvoted before + commentItem.setVoteType(0); + newVoteType = RedditUtils.DIR_UNVOTE; + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + } + + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); + + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position1) { + if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) { + commentItem.setVoteType(-1); + ((CommentViewHolder) holder).downvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + commentItem.setVoteType(0); + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + } + + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + commentItem.getVoteType())); + } + + @Override + public void onVoteThingFail(int position1) { + Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show(); + commentItem.setVoteType(previousVoteType); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(commentItem.getScore() + previousVoteType)); + ((CommentViewHolder) holder).upvoteButton.setColorFilter(previousUpvoteButtonColorFilter); + ((CommentViewHolder) holder).downvoteButton.setColorFilter(previousDownvoteButtonColorFilter); + } + }, commentItem.getFullName(), newVoteType, holder.getAdapterPosition()); + }); + } + + private void expandChildren(int position) { + mVisibleComments.get(position).setExpanded(true); + ArrayList children = mVisibleComments.get(position).getChildren(); + if(children != null && children.size() > 0) { + mVisibleComments.addAll(position + 1, children); + for(int i = position + 1; i <= position + children.size(); i++) { + mVisibleComments.get(i).setExpanded(false); + } + notifyItemRangeInserted(position + 1, children.size()); + } + } + + private void collapseChildren(int position) { + mVisibleComments.get(position).setExpanded(false); + int depth = mVisibleComments.get(position).getDepth(); + int allChildrenSize = 0; + for(int i = position + 1; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getDepth() > depth) { + allChildrenSize++; + } else { + break; + } + } + + mVisibleComments.subList(position + 1, position + 1 + allChildrenSize).clear(); + notifyItemRangeRemoved(position + 1, allChildrenSize); + } + + void addComments(ArrayList comments) { + int sizeBefore = mVisibleComments.size(); + mVisibleComments.addAll(comments); + notifyItemRangeInserted(sizeBefore, comments.size()); + } + + //Need proper implementation + void addComment(CommentData comment) { + mCommentData.add(0, comment); + notifyItemInserted(0); + } + + //Need proper implementation + void addChildComment(CommentData comment, int parentPosition) { + ArrayList childComments = mCommentData.get(parentPosition).getChildren(); + if(childComments == null) { + childComments = new ArrayList<>(); + } + childComments.add(0, comment); + mCommentData.get(parentPosition).addChildren(childComments); + mCommentData.get(parentPosition).setHasReply(true); + notifyItemChanged(parentPosition); + } + + @Override + public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { + if (holder instanceof CommentViewHolder) { + ((CommentViewHolder) holder).expandButton.setVisibility(View.GONE); + ((CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.GONE); + } + } + + @Override + public int getItemCount() { + return mVisibleComments.size(); + } + + class CommentViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.author_text_view_item_post_comment) TextView authorTextView; + @BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView; + @BindView(R.id.comment_markdown_view_item_post_comment) MarkwonView commentMarkdownView; + @BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton; + @BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView; + @BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton; + @BindView(R.id.load_more_comments_progress_bar) ProgressBar loadMoreCommentsProgressBar; + @BindView(R.id.expand_button_item_post_comment) ImageView expandButton; + @BindView(R.id.share_button_item_post_comment) ImageView shareButton; + @BindView(R.id.reply_button_item_post_comment) ImageView replyButton; + @BindView(R.id.vertical_block_item_post_comment) View verticalBlock; + + CommentViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java index c4b1958e..7f582214 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/FetchComment.java @@ -5,7 +5,6 @@ import android.util.Log; import androidx.annotation.NonNull; import java.util.ArrayList; -import java.util.List; import java.util.Locale; import retrofit2.Call; @@ -15,18 +14,18 @@ import retrofit2.Retrofit; class FetchComment { interface FetchCommentListener { - void onFetchCommentSuccess(List commentsData, + void onFetchCommentSuccess(ArrayList commentsData, String parentId, ArrayList children); void onFetchCommentFailed(); } interface FetchMoreCommentListener { - void onFetchMoreCommentSuccess(List commentsData, int childrenStartingIndex); + void onFetchMoreCommentSuccess(ArrayList commentsData, int childrenStartingIndex); void onFetchMoreCommentFailed(); } interface FetchAllCommentListener { - void onFetchAllCommentSuccess(List commentData); + void onFetchAllCommentSuccess(ArrayList commentData); void onFetchAllCommentFailed(); } @@ -43,10 +42,10 @@ class FetchComment { locale, isPost, parentDepth, new ParseComment.ParseCommentListener() { @Override - public void onParseCommentSuccess(List commentData, - String parentId, ArrayList children) { + public void onParseCommentSuccess(ArrayList commentData, + String parentId, ArrayList moreChildrenIds) { fetchCommentListener.onFetchCommentSuccess(commentData, parentId, - children); + moreChildrenIds); } @Override @@ -104,8 +103,8 @@ class FetchComment { ParseComment.parseMoreComment(response.body(), new ArrayList<>(), locale, 0, new ParseComment.ParseCommentListener() { @Override - public void onParseCommentSuccess(List commentData, String parentId, - ArrayList children) { + public void onParseCommentSuccess(ArrayList commentData, String parentId, + ArrayList moreChildrenIds) { fetchMoreCommentListener.onFetchMoreCommentSuccess(commentData, startingIndex + 100); } @@ -155,12 +154,12 @@ class FetchComment { fetchComment(retrofit, subredditNamePrefixed, article, comment, locale, isPost, parentDepth, new FetchCommentListener() { @Override - public void onFetchCommentSuccess(List commentsData, String parentId, ArrayList children) { + public void onFetchCommentSuccess(ArrayList commentsData, String parentId, ArrayList children) { if(children.size() != 0) { fetchMoreComment(retrofit, subredditNamePrefixed, parentId, children, 0, locale, new FetchMoreCommentListener() { @Override - public void onFetchMoreCommentSuccess(List commentsData, + public void onFetchMoreCommentSuccess(ArrayList commentsData, int childrenStartingIndex) { ((ArrayList) commentsData).addAll((ArrayList) commentsData); fetchAllCommentListener.onFetchAllCommentSuccess(commentsData); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java index 16aaa609..05b9440a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java @@ -3,6 +3,8 @@ package ml.docilealligator.infinityforreddit; import android.os.AsyncTask; import android.util.Log; +import androidx.annotation.Nullable; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -10,12 +12,11 @@ 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(List commentData, String parentId, ArrayList children); + void onParseCommentSuccess(ArrayList commentData, String parentId, ArrayList moreChildrenIds); void onParseCommentFailed(); } @@ -33,7 +34,8 @@ class ParseComment { boolean isPost, int parentDepth, ParseCommentListener parseCommentListener) { try { JSONArray childrenArray = new JSONArray(response); - + String parentId = childrenArray.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY) + .getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getString(JSONUtils.NAME_KEY); if(isPost) { childrenArray = childrenArray.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); } else { @@ -41,7 +43,8 @@ class ParseComment { .getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONObject(JSONUtils.REPLIES_KEY) .getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); } - new ParseCommentAsyncTask(childrenArray, commentData, locale, parentDepth, parseCommentListener).execute(); + + new ParseCommentAsyncTask(childrenArray, commentData, locale, parentId, parentDepth, parseCommentListener).execute(); } catch (JSONException e) { e.printStackTrace(); if(e.getMessage() != null) { @@ -59,7 +62,7 @@ class ParseComment { int parentDepth, ParseCommentListener parseCommentListener) { try { JSONArray childrenArray = new JSONObject(response).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); - new ParseCommentAsyncTask(childrenArray, commentData, locale, parentDepth, parseCommentListener).execute(); + new ParseCommentAsyncTask(childrenArray, commentData, locale, null, parentDepth, parseCommentListener).execute(); } catch (JSONException e) { e.printStackTrace(); if(e.getMessage() != null) { @@ -78,20 +81,21 @@ class ParseComment { private JSONArray comments; private ArrayList commentData; private ArrayList newcommentData; - private ArrayList children; + private ArrayList moreChildrenIds; private Locale locale; + private String parentId; private int parentDepth; private ParseCommentListener parseCommentListener; private boolean parseFailed; - private String parentId; ParseCommentAsyncTask(JSONArray comments, ArrayList commentData, Locale locale, - int parentDepth, ParseCommentListener parseCommentListener){ + @Nullable String parentId, int parentDepth, ParseCommentListener parseCommentListener){ this.comments = comments; this.commentData = commentData; newcommentData = new ArrayList<>(); - children = new ArrayList<>(); + moreChildrenIds = new ArrayList<>(); this.locale = locale; + this.parentId = parentId; this.parentDepth = parentDepth; parseFailed = false; this.parseCommentListener = parseCommentListener; @@ -100,32 +104,7 @@ class ParseComment { @Override protected Void doInBackground(Void... voids) { try { - int actualCommentLength; - - if(comments.length() == 0) { - return null; - } - - JSONObject more = comments.getJSONObject(comments.length() - 1).getJSONObject(JSONUtils.DATA_KEY); - - //Maybe children contain only comments and no more info - if(more.has(JSONUtils.COUNT_KEY)) { - JSONArray childrenArray = more.getJSONArray(JSONUtils.CHILDREN_KEY); - - parentId = more.getString(JSONUtils.PARENT_ID_KEY); - for(int i = 0; i < childrenArray.length(); i++) { - children.add(childrenArray.getString(i)); - } - - actualCommentLength = comments.length() - 1; - } else { - actualCommentLength = comments.length(); - } - - for (int i = 0; i < actualCommentLength; i++) { - JSONObject data = comments.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY); - newcommentData.add(parseSingleComment(data, parentDepth, locale)); - } + parseCommentRecursion(comments, newcommentData, moreChildrenIds, parentDepth, locale); } catch (JSONException e) { parseFailed = true; if(e.getMessage() != null) { @@ -139,13 +118,55 @@ class ParseComment { protected void onPostExecute(Void aVoid) { if(!parseFailed) { commentData.addAll(newcommentData); - parseCommentListener.onParseCommentSuccess(commentData, parentId, children); + parseCommentListener.onParseCommentSuccess(commentData, parentId, moreChildrenIds); } else { parseCommentListener.onParseCommentFailed(); } } } + private static void parseCommentRecursion(JSONArray comments, ArrayList newCommentData, + ArrayList moreChildrenIds, int parentDepth, Locale locale) throws JSONException { + int actualCommentLength; + + if(comments.length() == 0) { + return; + } + + JSONObject more = comments.getJSONObject(comments.length() - 1).getJSONObject(JSONUtils.DATA_KEY); + + //Maybe moreChildrenIds contain only comments and no more info + if(more.has(JSONUtils.COUNT_KEY)) { + JSONArray childrenArray = more.getJSONArray(JSONUtils.CHILDREN_KEY); + + for(int i = 0; i < childrenArray.length(); i++) { + moreChildrenIds.add(childrenArray.getString(i)); + } + + actualCommentLength = comments.length() - 1; + } else { + actualCommentLength = comments.length(); + } + + for (int i = 0; i < actualCommentLength; i++) { + JSONObject data = comments.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY); + CommentData singleComment = parseSingleComment(data, parentDepth, locale); + + if(data.get(JSONUtils.REPLIES_KEY) instanceof JSONObject) { + JSONArray childrenArray = data.getJSONObject(JSONUtils.REPLIES_KEY) + .getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY); + ArrayList children = new ArrayList<>(); + ArrayList nextMoreChildrenIds = new ArrayList<>(); + parseCommentRecursion(childrenArray, children, nextMoreChildrenIds, singleComment.getDepth(), + locale); + singleComment.addChildren(children); + singleComment.setMoreChildrenIds(nextMoreChildrenIds); + } + + newCommentData.add(singleComment); + } + } + private static class ParseMoreCommentBasicInfoAsyncTask extends AsyncTask { private JSONArray children; private StringBuilder commaSeparatedChildren; @@ -229,11 +250,11 @@ class ParseComment { } } } - private static CommentData parseSingleComment(JSONObject singleCommentData, int parentDepth, Locale locale) throws JSONException { String id = singleCommentData.getString(JSONUtils.ID_KEY); String fullName = singleCommentData.getString(JSONUtils.NAME_KEY); String author = singleCommentData.getString(JSONUtils.AUTHOR_KEY); + String parentId = singleCommentData.getString(JSONUtils.PARENT_ID_KEY); boolean isSubmitter = singleCommentData.getBoolean(JSONUtils.IS_SUBMITTER_KEY); String commentContent = ""; if(!singleCommentData.isNull(JSONUtils.BODY_HTML_KEY)) { @@ -251,14 +272,14 @@ class ParseComment { int depth; if(singleCommentData.has(JSONUtils.DEPTH_KEY)) { - depth = singleCommentData.getInt(JSONUtils.DEPTH_KEY) + parentDepth; + depth = singleCommentData.getInt(JSONUtils.DEPTH_KEY); } else { depth = parentDepth; } boolean collapsed = singleCommentData.getBoolean(JSONUtils.COLLAPSED_KEY); boolean hasReply = !(singleCommentData.get(JSONUtils.REPLIES_KEY) instanceof String); - return new CommentData(id, fullName, author, formattedSubmitTime, commentContent, score, + return new CommentData(id, fullName, author, formattedSubmitTime, commentContent, parentId, score, isSubmitter, permalink, depth, collapsed, hasReply, scoreHidden); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index 741a3a57..3c3db7b5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -28,6 +28,7 @@ import androidx.core.content.ContextCompat; import androidx.core.widget.NestedScrollView; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.RequestBuilder; @@ -41,14 +42,12 @@ import com.google.android.material.card.MaterialCardView; import com.google.android.material.chip.Chip; import com.google.android.material.snackbar.Snackbar; import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar; -import com.multilevelview.MultiLevelRecyclerView; import com.santalu.aspectratioimageview.AspectRatioImageView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; -import java.util.List; import java.util.Locale; import javax.inject.Inject; @@ -90,7 +89,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { private ArrayList children; private int mChildrenStartingIndex = 0; - private CommentMultiLevelRecyclerViewAdapter mAdapter; + private CommentRecyclerViewAdapter mAdapter; private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; @BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout; @@ -120,7 +119,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { @BindView(R.id.share_button_view_post_detail) ImageView mShareButton; @BindView(R.id.comment_progress_bar_view_post_detail) CircleProgressBar mCommentProgressbar; @BindView(R.id.comment_card_view_view_post_detail) MaterialCardView mCommentCardView; - @BindView(R.id.recycler_view_view_post_detail) MultiLevelRecyclerView mRecyclerView; + @BindView(R.id.recycler_view_view_post_detail) RecyclerView mRecyclerView; @BindView(R.id.no_comment_wrapper_linear_layout_view_post_detail) LinearLayout mNoCommentWrapperLinearLayout; @BindView(R.id.no_comment_image_view_view_post_detail) ImageView mNoCommentImageView; @@ -504,23 +503,18 @@ public class ViewPostDetailActivity extends AppCompatActivity { FetchComment.fetchComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getId(), null, mLocale, true, 0, new FetchComment.FetchCommentListener() { @Override - public void onFetchCommentSuccess(List commentsData, + public void onFetchCommentSuccess(ArrayList commentsData, String parentId, ArrayList children) { ViewPostDetailActivity.this.children = children; mCommentProgressbar.setVisibility(View.GONE); - mCommentsData.addAll((ArrayList) commentsData); + mCommentsData.addAll(commentsData); if (mCommentsData.size() > 0) { if(mAdapter == null) { - mAdapter = new CommentMultiLevelRecyclerViewAdapter( - ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit, - mSharedPreferences, mCommentsData, - mRecyclerView, mPost.getSubredditNamePrefixed(), - mPost.getId(), mLocale); + mAdapter = new CommentRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, + mOauthRetrofit, mSharedPreferences, commentsData, mRecyclerView, + mPost.getSubredditNamePrefixed(), mPost.getId(), mLocale); mRecyclerView.setAdapter(mAdapter); - mRecyclerView.removeItemClickListeners(); - mRecyclerView.setToggleItemOnClick(false); - mRecyclerView.setAccordion(false); mNestedScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> { if(!isLoadingMoreChildren) { @@ -556,8 +550,8 @@ public class ViewPostDetailActivity extends AppCompatActivity { FetchComment.fetchMoreComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getFullName(), children, startingIndex, mLocale, new FetchComment.FetchMoreCommentListener() { @Override - public void onFetchMoreCommentSuccess(List commentsData, int childrenStartingIndex) { - mAdapter.addComments((ArrayList) commentsData); + public void onFetchMoreCommentSuccess(ArrayList commentsData, int childrenStartingIndex) { + mAdapter.addComments(commentsData); mChildrenStartingIndex = childrenStartingIndex; isLoadingMoreChildren = false; } @@ -678,7 +672,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.action_refresh_view_post_detail_activity: refresh(); 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 1810f995..99056019 100644 --- a/app/src/main/res/layout/activity_view_post_detail.xml +++ b/app/src/main/res/layout/activity_view_post_detail.xml @@ -319,7 +319,12 @@ android:textColor="@color/primaryTextColor" android:textSize="18sp" /> - --> + + diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml index d04f78b6..a4a3c043 100644 --- a/app/src/main/res/layout/item_comment.xml +++ b/app/src/main/res/layout/item_comment.xml @@ -107,6 +107,7 @@ android:layout_toStartOf="@id/share_button_item_post_comment" android:layout_centerVertical="true" android:layout_marginEnd="16dp" + android:src="@drawable/ic_expand_less_black_20dp" android:tint="@android:color/tab_indicator_text" android:background="?actionBarItemBackground" android:clickable="true" -- cgit v1.2.3