Reimplement ViewPostActivity using one recyclerview to display a post and its comments instead of using a recyclerview inside NestedScrollView to prevent onBindViewHolder gets called for all the comments data at once and thus consumes more memory and freezes after the comments are loaded.

This commit is contained in:
Alex Ning 2019-06-25 09:21:44 +08:00
parent 34d49d884c
commit c4690a6e38
11 changed files with 927 additions and 846 deletions

View File

@ -3,55 +3,113 @@ package ml.docilealligator.infinityforreddit;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent; import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.DataSource;
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.google.android.material.chip.Chip;
import com.santalu.aspectratioimageview.AspectRatioImageView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
import CustomView.AspectRatioGifImageView;
import SubredditDatabase.SubredditRoomDatabase;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.view.MarkwonView; import ru.noties.markwon.view.MarkwonView;
class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int VIEW_TYPE_COMMENT = 0; private static final int VIEW_TYPE_POST_DETAIL = 0;
private static final int VIEW_TYPE_LOAD_MORE_COMMENT = 1; private static final int VIEW_TYPE_FIRST_LOADING = 1;
private static final int VIEW_TYPE_FIRST_LOADING_FAILED = 2;
private static final int VIEW_TYPE_NO_COMMENT_PLACEHOLDER = 3;
private static final int VIEW_TYPE_COMMENT = 4;
private static final int VIEW_TYPE_LOAD_MORE_COMMENT = 5;
private Activity mActivity; private Activity mActivity;
private Retrofit mRetrofit; private Retrofit mRetrofit;
private Retrofit mOauthRetrofit; private Retrofit mOauthRetrofit;
private RequestManager mGlide;
private SharedPreferences mSharedPreferences; private SharedPreferences mSharedPreferences;
private Post mPost;
private ArrayList<CommentData> mVisibleComments;
private String mSubredditNamePrefixed; private String mSubredditNamePrefixed;
private Locale mLocale; private Locale mLocale;
private UpdatePostInPostFragmentCallback mUpdatePostInPostFragmentCallback;
private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask;
private boolean isInitiallyLoading;
private boolean isInitiallyLoadingFailed;
private ArrayList<CommentData> mVisibleComments; interface UpdatePostInPostFragmentCallback {
void updatePost(Post post);
}
CommentRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, CommentRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, RequestManager glide,
SharedPreferences sharedPreferences, ArrayList<CommentData> expandedComments, SharedPreferences sharedPreferences, Post post, String subredditNamePrefixed,
String subredditNamePrefixed, Locale locale) { Locale locale, LoadSubredditIconAsyncTask loadSubredditIconAsyncTask,
UpdatePostInPostFragmentCallback updatePostInPostFragmentCallback) {
mActivity = activity; mActivity = activity;
mRetrofit = retrofit; mRetrofit = retrofit;
mOauthRetrofit = oauthRetrofit; mOauthRetrofit = oauthRetrofit;
mGlide = glide;
mSharedPreferences = sharedPreferences; mSharedPreferences = sharedPreferences;
mPost = post;
mVisibleComments = new ArrayList<>();
mSubredditNamePrefixed = subredditNamePrefixed; mSubredditNamePrefixed = subredditNamePrefixed;
mLocale = locale; mLocale = locale;
mVisibleComments = expandedComments; mLoadSubredditIconAsyncTask = loadSubredditIconAsyncTask;
mUpdatePostInPostFragmentCallback = updatePostInPostFragmentCallback;
isInitiallyLoading = true;
isInitiallyLoadingFailed = false;
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
CommentData comment = mVisibleComments.get(position); if(position == 0) {
return VIEW_TYPE_POST_DETAIL;
}
if(mVisibleComments.size() == 0) {
if(position == 1) {
if(isInitiallyLoading) {
return VIEW_TYPE_FIRST_LOADING;
} else if(isInitiallyLoadingFailed) {
return VIEW_TYPE_FIRST_LOADING_FAILED;
} else {
return VIEW_TYPE_NO_COMMENT_PLACEHOLDER;
}
}
}
CommentData comment = mVisibleComments.get(position - 1);
if(!comment.isPlaceHolder()) { if(!comment.isPlaceHolder()) {
return VIEW_TYPE_COMMENT; return VIEW_TYPE_COMMENT;
} else { } else {
@ -62,7 +120,15 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_COMMENT) { if(viewType == VIEW_TYPE_POST_DETAIL) {
return new PostDetailViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail, parent, false));
} else if(viewType == VIEW_TYPE_FIRST_LOADING) {
return new LoadCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments, parent, false));
} else if(viewType == VIEW_TYPE_FIRST_LOADING_FAILED) {
return new LoadCommentsFailedViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments_failed_placeholder, parent, false));
} else if(viewType == VIEW_TYPE_NO_COMMENT_PLACEHOLDER) {
return new NoCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_no_comment_placeholder, parent, false));
} else if(viewType == VIEW_TYPE_COMMENT) {
return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false)); return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false));
} else { } else {
return new LoadMoreCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_comments_placeholder, parent, false)); return new LoadMoreCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_comments_placeholder, parent, false));
@ -71,8 +137,196 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(holder.getItemViewType() == VIEW_TYPE_COMMENT) { if(holder.getItemViewType() == VIEW_TYPE_POST_DETAIL) {
CommentData commentItem = mVisibleComments.get(holder.getAdapterPosition()); ((PostDetailViewHolder) holder).mTitleTextView.setText(mPost.getTitle());
if(mPost.getSubredditIconUrl() == null) {
if(mLoadSubredditIconAsyncTask != null) {
mLoadSubredditIconAsyncTask.cancel(true);
} else {
mLoadSubredditIconAsyncTask = new LoadSubredditIconAsyncTask(
SubredditRoomDatabase.getDatabase(mActivity).subredditDao(), mPost.getSubredditNamePrefixed().substring(2),
iconImageUrl -> {
if(!iconImageUrl.equals("")) {
mGlide.load(iconImageUrl)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(((PostDetailViewHolder) holder).mSubredditIconGifImageView);
} else {
mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(((PostDetailViewHolder) holder).mSubredditIconGifImageView);
}
mPost.setSubredditIconUrl(iconImageUrl);
});
}
mLoadSubredditIconAsyncTask.execute();
} else if(!mPost.getSubredditIconUrl().equals("")) {
mGlide.load(mPost.getSubredditIconUrl())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(((PostDetailViewHolder) holder).mSubredditIconGifImageView);
} else {
mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(((PostDetailViewHolder) holder).mSubredditIconGifImageView);
}
switch (mPost.getVoteType()) {
case 1:
//Upvote
((PostDetailViewHolder) holder).mUpvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), PorterDuff.Mode.SRC_IN);
break;
case -1:
//Downvote
((PostDetailViewHolder) holder).mDownvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), PorterDuff.Mode.SRC_IN);
break;
case 0:
((PostDetailViewHolder) holder).mUpvoteButton.clearColorFilter();
((PostDetailViewHolder) holder).mDownvoteButton.clearColorFilter();
}
if(mPost.getPostType() != Post.TEXT_TYPE && mPost.getPostType() != Post.NO_PREVIEW_LINK_TYPE) {
((PostDetailViewHolder) holder).mRelativeLayout.setVisibility(View.VISIBLE);
((PostDetailViewHolder) holder).mImageView.setVisibility(View.VISIBLE);
((PostDetailViewHolder) holder).mImageView.setRatio((float) mPost.getPreviewHeight() / (float) mPost.getPreviewWidth());
loadImage((PostDetailViewHolder) holder);
} else {
((PostDetailViewHolder) holder).mRelativeLayout.setVisibility(View.GONE);
((PostDetailViewHolder) holder).mImageView.setVisibility(View.GONE);
}
if(mPost.isCrosspost()) {
((PostDetailViewHolder) holder).mCrosspostImageView.setVisibility(View.VISIBLE);
}
((PostDetailViewHolder) holder).mSubredditTextView.setText(mPost.getSubredditNamePrefixed());
((PostDetailViewHolder) holder).mPostTimeTextView.setText(mPost.getPostTime());
if(mPost.getGilded() > 0) {
((PostDetailViewHolder) holder).mGildedImageView.setVisibility(View.VISIBLE);
mGlide.load(R.drawable.gold).into(((PostDetailViewHolder) holder).mGildedImageView);
((PostDetailViewHolder) holder).mGildedNumberTextView.setVisibility(View.VISIBLE);
String gildedNumber = mActivity.getResources().getString(R.string.gilded, mPost.getGilded());
((PostDetailViewHolder) holder).mGildedNumberTextView.setText(gildedNumber);
}
if(mPost.isNSFW()) {
((PostDetailViewHolder) holder).mNSFWChip.setVisibility(View.VISIBLE);
} else {
((PostDetailViewHolder) holder).mNSFWChip.setVisibility(View.GONE);
}
String scoreWithVote = Integer.toString(mPost.getScore() + mPost.getVoteType());
((PostDetailViewHolder) holder).mScoreTextView.setText(scoreWithVote);
switch (mPost.getPostType()) {
case Post.IMAGE_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("IMAGE");
((PostDetailViewHolder) holder).mImageView.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, ViewImageActivity.class);
intent.putExtra(ViewImageActivity.IMAGE_URL_KEY, mPost.getUrl());
intent.putExtra(ViewImageActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewImageActivity.FILE_NAME_KEY, mPost.getSubredditNamePrefixed().substring(2)
+ "-" + mPost.getId().substring(3));
mActivity.startActivity(intent);
});
break;
case Post.LINK_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("LINK");
((PostDetailViewHolder) holder).linkTextView.setVisibility(View.VISIBLE);
String domain = Uri.parse(mPost.getUrl()).getHost();
((PostDetailViewHolder) holder).linkTextView.setText(domain);
((PostDetailViewHolder) holder).mImageView.setOnClickListener(view -> {
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(mPost.getUrl()));
});
break;
case Post.GIF_VIDEO_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("GIF");
final Uri gifVideoUri = Uri.parse(mPost.getVideoUrl());
((PostDetailViewHolder) holder).mImageView.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, ViewVideoActivity.class);
intent.setData(gifVideoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPost.isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPost.isDownloadableGifOrVideo());
if(mPost.isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPost.getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, mPost.getSubredditNamePrefixed());
intent.putExtra(ViewVideoActivity.ID_KEY, mPost.getId());
}
mActivity.startActivity(intent);
});
break;
case Post.VIDEO_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("VIDEO");
final Uri videoUri = Uri.parse(mPost.getVideoUrl());
((PostDetailViewHolder) holder).mImageView.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, ViewVideoActivity.class);
intent.setData(videoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPost.isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPost.isDownloadableGifOrVideo());
if(mPost.isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPost.getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, mPost.getSubredditNamePrefixed());
intent.putExtra(ViewVideoActivity.ID_KEY, mPost.getId());
}
mActivity.startActivity(intent);
});
break;
case Post.NO_PREVIEW_LINK_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("LINK");
((PostDetailViewHolder) holder).linkTextView.setVisibility(View.VISIBLE);
String noPreviewLinkDomain = Uri.parse(mPost.getUrl()).getHost();
((PostDetailViewHolder) holder).linkTextView.setText(noPreviewLinkDomain);
if(!mPost.getSelfText().equals("")) {
((PostDetailViewHolder) holder).mContentMarkdownView.setVisibility(View.VISIBLE);
((PostDetailViewHolder) holder).mContentMarkdownView.setMarkdown(getCustomSpannableConfiguration(), mPost.getSelfText());
}
((PostDetailViewHolder) holder).mNoPreviewLinkImageView.setVisibility(View.VISIBLE);
((PostDetailViewHolder) holder).mNoPreviewLinkImageView.setOnClickListener(view -> {
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(mPost.getUrl()));
});
break;
case Post.TEXT_TYPE:
((PostDetailViewHolder) holder).mTypeChip.setText("TEXT");
if(!mPost.getSelfText().equals("")) {
((PostDetailViewHolder) holder).mContentMarkdownView.setVisibility(View.VISIBLE);
((PostDetailViewHolder) holder).mContentMarkdownView.setMarkdown(getCustomSpannableConfiguration(), mPost.getSelfText());
}
break;
}
} else if(holder.getItemViewType() == VIEW_TYPE_COMMENT) {
CommentData commentItem;
if(isInitiallyLoading || isInitiallyLoadingFailed) {
commentItem = mVisibleComments.get(holder.getAdapterPosition() - 2);
} else {
commentItem = mVisibleComments.get(holder.getAdapterPosition() - 1);
}
String authorPrefixed = "u/" + commentItem.getAuthor(); String authorPrefixed = "u/" + commentItem.getAuthor();
((CommentViewHolder) holder).authorTextView.setText(authorPrefixed); ((CommentViewHolder) holder).authorTextView.setText(authorPrefixed);
@ -122,11 +376,17 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
.setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); .setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
break; break;
} }
} else { } else if(holder instanceof LoadMoreCommentViewHolder) {
((LoadMoreCommentViewHolder) holder).verticalBlock.getLayoutParams().width = mVisibleComments.get(holder.getAdapterPosition()).getDepth() * 16; CommentData placeholder;
if(mVisibleComments.get(holder.getAdapterPosition()).isLoadingMoreChildren()) { if(isInitiallyLoading || isInitiallyLoadingFailed) {
placeholder = mVisibleComments.get(holder.getAdapterPosition() - 2);
} else {
placeholder = mVisibleComments.get(holder.getAdapterPosition() - 1);
}
((LoadMoreCommentViewHolder) holder).verticalBlock.getLayoutParams().width = placeholder.getDepth() * 16;
if(placeholder.isLoadingMoreChildren()) {
((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.loading); ((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.loading);
} else if(mVisibleComments.get(holder.getAdapterPosition()).isLoadMoreChildrenFailed()) { } else if(placeholder.isLoadMoreChildrenFailed()) {
((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments_failed); ((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments_failed);
} else { } else {
((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments); ((LoadMoreCommentViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments);
@ -134,6 +394,63 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
} }
} }
private void loadImage(PostDetailViewHolder holder) {
RequestBuilder imageRequestBuilder = mGlide.load(mPost.getPreviewUrl())
.apply(new RequestOptions().override(mPost.getPreviewWidth(), mPost.getPreviewHeight()))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
holder.mLoadImageProgressBar.setVisibility(View.GONE);
holder.mLoadImageErrorTextView.setVisibility(View.VISIBLE);
holder.mLoadImageErrorTextView.setOnClickListener(view -> {
holder.mLoadImageProgressBar.setVisibility(View.VISIBLE);
holder.mLoadImageErrorTextView.setVisibility(View.GONE);
loadImage(holder);
});
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
holder.mLoadWrapper.setVisibility(View.GONE);
return false;
}
});
if(mPost.isNSFW()) {
imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 2)))
.into(holder.mImageView);
} else {
imageRequestBuilder.into(holder.mImageView);
}
}
private SpannableConfiguration getCustomSpannableConfiguration() {
return 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();
}
void updatePost(Post post) {
mPost = post;
notifyItemChanged(0);
}
private int getParentPosition(int position) { private int getParentPosition(int position) {
int childDepth = mVisibleComments.get(position).getDepth(); int childDepth = mVisibleComments.get(position).getDepth();
for(int i = position; i >= 0; i--) { for(int i = position; i >= 0; i--) {
@ -176,9 +493,19 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
} }
void addComments(ArrayList<CommentData> comments) { void addComments(ArrayList<CommentData> comments) {
if(mVisibleComments.size() == 0) {
isInitiallyLoading = false;
isInitiallyLoadingFailed = false;
if(comments.size() == 0) {
notifyItemChanged(1);
} else {
notifyItemRemoved(1);
}
}
int sizeBefore = mVisibleComments.size(); int sizeBefore = mVisibleComments.size();
mVisibleComments.addAll(comments); mVisibleComments.addAll(comments);
notifyItemRangeInserted(sizeBefore, comments.size()); notifyItemRangeInserted(sizeBefore + 1, comments.size());
} }
void addComment(CommentData comment) { void addComment(CommentData comment) {
@ -207,9 +534,36 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
} }
} }
void clearData() { void initiallyLoading() {
mVisibleComments.clear(); if(mLoadSubredditIconAsyncTask != null) {
notifyDataSetChanged(); mLoadSubredditIconAsyncTask.cancel(true);
}
if(isInitiallyLoading || isInitiallyLoadingFailed) {
isInitiallyLoading = true;
isInitiallyLoadingFailed = false;
notifyItemChanged(1);
} else {
isInitiallyLoading = true;
isInitiallyLoadingFailed = false;
notifyItemInserted(1);
}
clearComments();
}
void initiallyLoadCommentsFailed() {
isInitiallyLoading = false;
isInitiallyLoadingFailed = true;
notifyItemChanged(1);
}
private void clearComments() {
if(mVisibleComments.size() != 0) {
int previousSize = mVisibleComments.size();
mVisibleComments.clear();
notifyItemRangeRemoved(1, previousSize);
}
} }
@Override @Override
@ -221,7 +575,164 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
@Override @Override
public int getItemCount() { public int getItemCount() {
return mVisibleComments.size(); if(isInitiallyLoading || isInitiallyLoadingFailed) {
return 2;
}
return mVisibleComments.size() + 1;
}
class PostDetailViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.subreddit_icon_name_linear_layout_item_post_detail) LinearLayout mSubredditIconNameLinearLayout;
@BindView(R.id.subreddit_icon_circle_image_view_item_post_detail) AspectRatioGifImageView mSubredditIconGifImageView;
@BindView(R.id.subreddit_text_view_item_post_detail) TextView mSubredditTextView;
@BindView(R.id.post_time_text_view_item_post_detail) TextView mPostTimeTextView;
@BindView(R.id.title_text_view_item_post_detail) TextView mTitleTextView;
@BindView(R.id.content_markdown_view_item_post_detail) MarkwonView mContentMarkdownView;
@BindView(R.id.type_text_view_item_post_detail) Chip mTypeChip;
@BindView(R.id.gilded_image_view_item_post_detail) ImageView mGildedImageView;
@BindView(R.id.gilded_number_text_view_item_post_detail) TextView mGildedNumberTextView;
@BindView(R.id.crosspost_image_view_item_post_detail) ImageView mCrosspostImageView;
@BindView(R.id.nsfw_text_view_item_post_detail) Chip mNSFWChip;
@BindView(R.id.link_text_view_item_post_detail) TextView linkTextView;
@BindView(R.id.image_view_wrapper_item_post_detail) RelativeLayout mRelativeLayout;
@BindView(R.id.load_wrapper_item_post_detail) RelativeLayout mLoadWrapper;
@BindView(R.id.progress_bar_item_post_detail) ProgressBar mLoadImageProgressBar;
@BindView(R.id.load_image_error_text_view_item_post_detail) TextView mLoadImageErrorTextView;
@BindView(R.id.image_view_item_post_detail) AspectRatioImageView mImageView;
@BindView(R.id.image_view_no_preview_link_item_post_detail) ImageView mNoPreviewLinkImageView;
@BindView(R.id.plus_button_item_post_detail) ImageView mUpvoteButton;
@BindView(R.id.score_text_view_item_post_detail) TextView mScoreTextView;
@BindView(R.id.minus_button_item_post_detail) ImageView mDownvoteButton;
@BindView(R.id.share_button_item_post_detail) ImageView mShareButton;
public PostDetailViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
mSubredditIconNameLinearLayout.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY,
mPost.getSubredditNamePrefixed().substring(2));
mActivity.startActivity(intent);
});
mShareButton.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
String extraText = mPost.getTitle() + "\n" + mPost.getPermalink();
intent.putExtra(Intent.EXTRA_TEXT, extraText);
mActivity.startActivity(Intent.createChooser(intent, "Share"));
});
mUpvoteButton.setOnClickListener(view -> {
ColorFilter previousUpvoteButtonColorFilter = mUpvoteButton.getColorFilter();
ColorFilter previousDownvoteButtonColorFilter = mDownvoteButton.getColorFilter();
int previousVoteType = mPost.getVoteType();
String newVoteType;
mDownvoteButton.clearColorFilter();
if(previousUpvoteButtonColorFilter == null) {
//Not upvoted before
mPost.setVoteType(1);
newVoteType = RedditUtils.DIR_UPVOTE;
mUpvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
//Upvoted before
mPost.setVoteType(0);
newVoteType = RedditUtils.DIR_UNVOTE;
mUpvoteButton.clearColorFilter();
}
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
mUpdatePostInPostFragmentCallback.updatePost(mPost);
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override
public void onVoteThingSuccess() {
if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) {
mPost.setVoteType(1);
mUpvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
mPost.setVoteType(0);
mUpvoteButton.clearColorFilter();
}
mDownvoteButton.clearColorFilter();
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
mUpdatePostInPostFragmentCallback.updatePost(mPost);
}
@Override
public void onVoteThingFail() {
Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show();
mPost.setVoteType(previousVoteType);
mScoreTextView.setText(Integer.toString(mPost.getScore() + previousVoteType));
mUpvoteButton.setColorFilter(previousUpvoteButtonColorFilter);
mDownvoteButton.setColorFilter(previousDownvoteButtonColorFilter);
mUpdatePostInPostFragmentCallback.updatePost(mPost);
}
}, mPost.getFullName(), newVoteType);
});
mDownvoteButton.setOnClickListener(view -> {
ColorFilter previousUpvoteButtonColorFilter = mUpvoteButton.getColorFilter();
ColorFilter previousDownvoteButtonColorFilter = mDownvoteButton.getColorFilter();
int previousVoteType = mPost.getVoteType();
String newVoteType;
mUpvoteButton.clearColorFilter();
if(previousDownvoteButtonColorFilter == null) {
//Not upvoted before
mPost.setVoteType(-1);
newVoteType = RedditUtils.DIR_DOWNVOTE;
mDownvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
//Upvoted before
mPost.setVoteType(0);
newVoteType = RedditUtils.DIR_UNVOTE;
mDownvoteButton.clearColorFilter();
}
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
mUpdatePostInPostFragmentCallback.updatePost(mPost);
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override
public void onVoteThingSuccess() {
if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) {
mPost.setVoteType(-1);
mDownvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
mPost.setVoteType(0);
mDownvoteButton.clearColorFilter();
}
mUpvoteButton.clearColorFilter();
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
mUpdatePostInPostFragmentCallback.updatePost(mPost);
}
@Override
public void onVoteThingFail() {
Toast.makeText(mActivity, R.string.vote_failed, Toast.LENGTH_SHORT).show();
mPost.setVoteType(previousVoteType);
mScoreTextView.setText(Integer.toString(mPost.getScore() + previousVoteType));
mUpvoteButton.setColorFilter(previousUpvoteButtonColorFilter);
mDownvoteButton.setColorFilter(previousDownvoteButtonColorFilter);
mUpdatePostInPostFragmentCallback.updatePost(mPost);
}
}, mPost.getFullName(), newVoteType);
});
}
} }
class CommentViewHolder extends RecyclerView.ViewHolder { class CommentViewHolder extends RecyclerView.ViewHolder {
@ -242,117 +753,117 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
authorTextView.setOnClickListener(view -> { authorTextView.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); Intent intent = new Intent(mActivity, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mVisibleComments.get(getAdapterPosition()).getAuthor()); intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getAuthor());
mActivity.startActivity(intent); mActivity.startActivity(intent);
}); });
shareButton.setOnClickListener(view -> { shareButton.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_SEND); Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain"); intent.setType("text/plain");
String extraText = mVisibleComments.get(getAdapterPosition()).getPermalink(); String extraText = mVisibleComments.get(getAdapterPosition() - 1).getPermalink();
intent.putExtra(Intent.EXTRA_TEXT, extraText); intent.putExtra(Intent.EXTRA_TEXT, extraText);
mActivity.startActivity(Intent.createChooser(intent, "Share")); mActivity.startActivity(Intent.createChooser(intent, "Share"));
}); });
expandButton.setOnClickListener(view -> { expandButton.setOnClickListener(view -> {
if(mVisibleComments.get(getAdapterPosition()).isExpanded()) { if(mVisibleComments.get(getAdapterPosition() - 1).isExpanded()) {
collapseChildren(getAdapterPosition()); collapseChildren(getAdapterPosition());
expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp);
} else { } else {
expandChildren(getAdapterPosition()); expandChildren(getAdapterPosition());
mVisibleComments.get(getAdapterPosition()).setExpanded(true); mVisibleComments.get(getAdapterPosition() - 1).setExpanded(true);
expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp);
} }
}); });
replyButton.setOnClickListener(view -> { replyButton.setOnClickListener(view -> {
Intent intent = new Intent(mActivity, CommentActivity.class); Intent intent = new Intent(mActivity, CommentActivity.class);
intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, mVisibleComments.get(getAdapterPosition()).getDepth() + 1); intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, mVisibleComments.get(getAdapterPosition() - 1).getDepth() + 1);
intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, mVisibleComments.get(getAdapterPosition()).getCommentContent()); intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, mVisibleComments.get(getAdapterPosition() - 1).getCommentContent());
intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mVisibleComments.get(getAdapterPosition()).getFullName()); intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getFullName());
intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true); intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true);
intent.putExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, getAdapterPosition()); intent.putExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, getAdapterPosition());
mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE); mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE);
}); });
upvoteButton.setOnClickListener(view -> { upvoteButton.setOnClickListener(view -> {
int previousVoteType = mVisibleComments.get(getAdapterPosition()).getVoteType(); int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType();
String newVoteType; String newVoteType;
downvoteButton.clearColorFilter(); downvoteButton.clearColorFilter();
if(previousVoteType != CommentData.VOTE_TYPE_UPVOTE) { if(previousVoteType != CommentData.VOTE_TYPE_UPVOTE) {
//Not upvoted before //Not upvoted before
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_UPVOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE);
newVoteType = RedditUtils.DIR_UPVOTE; newVoteType = RedditUtils.DIR_UPVOTE;
upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else { } else {
//Upvoted before //Upvoted before
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
newVoteType = RedditUtils.DIR_UNVOTE; newVoteType = RedditUtils.DIR_UNVOTE;
upvoteButton.clearColorFilter(); upvoteButton.clearColorFilter();
} }
scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition()).getScore() + mVisibleComments.get(getAdapterPosition()).getVoteType())); scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType()));
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position) { public void onVoteThingSuccess(int position) {
if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) { if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) {
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_UPVOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE);
upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else { } else {
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
upvoteButton.clearColorFilter(); upvoteButton.clearColorFilter();
} }
downvoteButton.clearColorFilter(); downvoteButton.clearColorFilter();
scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition()).getScore() + mVisibleComments.get(getAdapterPosition()).getVoteType())); scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType()));
} }
@Override @Override
public void onVoteThingFail(int position) { } public void onVoteThingFail(int position) { }
}, mVisibleComments.get(getAdapterPosition()).getFullName(), newVoteType, getAdapterPosition()); }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition());
}); });
downvoteButton.setOnClickListener(view -> { downvoteButton.setOnClickListener(view -> {
int previousVoteType = mVisibleComments.get(getAdapterPosition()).getVoteType(); int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType();
String newVoteType; String newVoteType;
upvoteButton.clearColorFilter(); upvoteButton.clearColorFilter();
if(previousVoteType != CommentData.VOTE_TYPE_DOWNVOTE) { if(previousVoteType != CommentData.VOTE_TYPE_DOWNVOTE) {
//Not downvoted before //Not downvoted before
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE);
newVoteType = RedditUtils.DIR_DOWNVOTE; newVoteType = RedditUtils.DIR_DOWNVOTE;
downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else { } else {
//Downvoted before //Downvoted before
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
newVoteType = RedditUtils.DIR_UNVOTE; newVoteType = RedditUtils.DIR_UNVOTE;
downvoteButton.clearColorFilter(); downvoteButton.clearColorFilter();
} }
scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition()).getScore() + mVisibleComments.get(getAdapterPosition()).getVoteType())); scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType()));
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
@Override @Override
public void onVoteThingSuccess(int position1) { public void onVoteThingSuccess(int position1) {
if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) { if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) {
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE);
downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else { } else {
mVisibleComments.get(getAdapterPosition()).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE);
downvoteButton.clearColorFilter(); downvoteButton.clearColorFilter();
} }
upvoteButton.clearColorFilter(); upvoteButton.clearColorFilter();
scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition()).getScore() + mVisibleComments.get(getAdapterPosition()).getVoteType())); scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType()));
} }
@Override @Override
public void onVoteThingFail(int position1) { } public void onVoteThingFail(int position1) { }
}, mVisibleComments.get(getAdapterPosition()).getFullName(), newVoteType, getAdapterPosition()); }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition());
}); });
} }
} }
@ -366,11 +877,11 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
ButterKnife.bind(this, itemView); ButterKnife.bind(this, itemView);
placeholderTextView.setOnClickListener(view -> { placeholderTextView.setOnClickListener(view -> {
int parentPosition = getParentPosition(getAdapterPosition()); int parentPosition = getParentPosition(getAdapterPosition() - 1);
CommentData parentComment = mVisibleComments.get(parentPosition); CommentData parentComment = mVisibleComments.get(parentPosition);
mVisibleComments.get(getAdapterPosition()).setLoadingMoreChildren(true); mVisibleComments.get(getAdapterPosition() - 1).setLoadingMoreChildren(true);
mVisibleComments.get(getAdapterPosition()).setLoadMoreChildrenFailed(false); mVisibleComments.get(getAdapterPosition() - 1).setLoadMoreChildrenFailed(false);
placeholderTextView.setText(R.string.loading); placeholderTextView.setText(R.string.loading);
FetchComment.fetchMoreComment(mRetrofit, mSubredditNamePrefixed, parentComment.getMoreChildrenFullnames(), FetchComment.fetchMoreComment(mRetrofit, mSubredditNamePrefixed, parentComment.getMoreChildrenFullnames(),
@ -389,8 +900,8 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1)
.setLoadMoreChildrenFailed(false); .setLoadMoreChildrenFailed(false);
int placeholderPosition = getAdapterPosition(); int placeholderPosition = getAdapterPosition() - 1;
if(mVisibleComments.get(getAdapterPosition()).getFullName().equals(parentComment.getFullName())) { if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) {
for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) {
if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) {
placeholderPosition = i; placeholderPosition = i;
@ -404,14 +915,14 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
placeholderTextView.setText(R.string.comment_load_more_comments); placeholderTextView.setText(R.string.comment_load_more_comments);
mVisibleComments.addAll(placeholderPosition, expandedComments); mVisibleComments.addAll(placeholderPosition, expandedComments);
notifyItemRangeInserted(placeholderPosition, expandedComments.size()); notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size());
} else { } else {
mVisibleComments.get(parentPosition).getChildren() mVisibleComments.get(parentPosition).getChildren()
.remove(mVisibleComments.get(parentPosition).getChildren().size() - 1); .remove(mVisibleComments.get(parentPosition).getChildren().size() - 1);
mVisibleComments.get(parentPosition).removeMoreChildrenFullnames(); mVisibleComments.get(parentPosition).removeMoreChildrenFullnames();
int placeholderPosition = getAdapterPosition(); int placeholderPosition = getAdapterPosition() - 1;
if(mVisibleComments.get(getAdapterPosition()).getFullName().equals(parentComment.getFullName())) { if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) {
for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) {
if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) {
placeholderPosition = i; placeholderPosition = i;
@ -421,10 +932,10 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
} }
mVisibleComments.remove(placeholderPosition); mVisibleComments.remove(placeholderPosition);
notifyItemRemoved(placeholderPosition); notifyItemRemoved(placeholderPosition + 1);
mVisibleComments.addAll(placeholderPosition, expandedComments); mVisibleComments.addAll(placeholderPosition, expandedComments);
notifyItemRangeInserted(placeholderPosition, expandedComments.size()); notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size());
} }
} else { } else {
if(mVisibleComments.get(parentPosition).hasReply() && mVisibleComments.get(parentPosition).getChildren().size() <= childrenStartingIndex) { if(mVisibleComments.get(parentPosition).hasReply() && mVisibleComments.get(parentPosition).getChildren().size() <= childrenStartingIndex) {
@ -455,7 +966,7 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
placeholderTextView.setText(R.string.comment_load_more_comments); placeholderTextView.setText(R.string.comment_load_more_comments);
mVisibleComments.addAll(placeholderPosition, expandedComments); mVisibleComments.addAll(placeholderPosition, expandedComments);
notifyItemRangeInserted(placeholderPosition, expandedComments.size()); notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size());
} }
mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1) mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1)
@ -475,8 +986,8 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
if(parentPosition < mVisibleComments.size() if(parentPosition < mVisibleComments.size()
&& parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) { && parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) {
if(mVisibleComments.get(parentPosition).isExpanded()) { if(mVisibleComments.get(parentPosition).isExpanded()) {
int placeholderPosition = getAdapterPosition(); int placeholderPosition = getAdapterPosition() - 1;
if(!mVisibleComments.get(getAdapterPosition()).getFullName().equals(parentComment.getFullName())) { if(!mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) {
for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) {
if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) {
placeholderPosition = i; placeholderPosition = i;
@ -525,4 +1036,25 @@ class CommentRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}); });
} }
} }
class LoadCommentsViewHolder extends RecyclerView.ViewHolder {
public LoadCommentsViewHolder(@NonNull View itemView) {
super(itemView);
}
}
class LoadCommentsFailedViewHolder extends RecyclerView.ViewHolder {
public LoadCommentsFailedViewHolder(@NonNull View itemView) {
super(itemView);
}
}
class NoCommentViewHolder extends RecyclerView.ViewHolder {
public NoCommentViewHolder(@NonNull View itemView) {
super(itemView);
}
}
} }

View File

@ -106,7 +106,7 @@ class FetchComment {
} }
@Override @Override
public void onFailure(Call<String> call, Throwable t) { public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
Log.i("more comment failed", t.getMessage()); Log.i("more comment failed", t.getMessage());
fetchMoreCommentListener.onFetchMoreCommentFailed(); fetchMoreCommentListener.onFetchMoreCommentFailed();
} }

View File

@ -34,6 +34,8 @@ class LoadSubredditIconAsyncTask extends AsyncTask<Void, Void, Void> {
@Override @Override
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid); super.onPostExecute(aVoid);
loadSubredditIconAsyncTaskListener.loadIconSuccess(iconImageUrl); if(!isCancelled()) {
loadSubredditIconAsyncTaskListener.loadIconSuccess(iconImageUrl);
}
} }
} }

View File

@ -16,7 +16,7 @@ public interface RedditAPI {
@POST("api/v1/access_token") @POST("api/v1/access_token")
Call<String> getAccessToken(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params); Call<String> getAccessToken(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);
@GET("{subredditNamePrefixed}/comments/{article}.json?raw_json=1") @GET("{subredditNamePrefixed}/comments/{article}.json?&raw_json=1")
Call<String> getComments(@Path("subredditNamePrefixed") String subredditNamePrefixed, Call<String> getComments(@Path("subredditNamePrefixed") String subredditNamePrefixed,
@Path("article") String article); @Path("article") String article);

View File

@ -3,46 +3,23 @@ package ml.docilealligator.infinityforreddit;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.ColorFilter;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.RequestManager; import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.DataSource;
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.google.android.material.card.MaterialCardView;
import com.google.android.material.chip.Chip;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
import com.santalu.aspectratioimageview.AspectRatioImageView;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
@ -53,15 +30,9 @@ import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import CustomView.AspectRatioGifImageView;
import SubredditDatabase.SubredditRoomDatabase;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import retrofit2.Retrofit; import retrofit2.Retrofit;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.view.MarkwonView;
import static ml.docilealligator.infinityforreddit.CommentActivity.EXTRA_COMMENT_DATA_KEY; import static ml.docilealligator.infinityforreddit.CommentActivity.EXTRA_COMMENT_DATA_KEY;
import static ml.docilealligator.infinityforreddit.CommentActivity.WRITE_COMMENT_REQUEST_CODE; import static ml.docilealligator.infinityforreddit.CommentActivity.WRITE_COMMENT_REQUEST_CODE;
@ -93,34 +64,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
@BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout; @BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout;
@BindView(R.id.toolbar_view_post_detail_activity) Toolbar toolbar; @BindView(R.id.toolbar_view_post_detail_activity) Toolbar toolbar;
@BindView(R.id.nested_scroll_view_view_post_detail_activity) NestedScrollView mNestedScrollView;
@BindView(R.id.subreddit_icon_name_linear_layout_view_post_detail) LinearLayout mSubredditIconNameLinearLayout;
@BindView(R.id.subreddit_icon_circle_image_view_view_post_detail) AspectRatioGifImageView mSubredditIconGifImageView;
@BindView(R.id.subreddit_text_view_view_post_detail) TextView mSubredditTextView;
@BindView(R.id.post_time_text_view_view_post_detail) TextView mPostTimeTextView;
@BindView(R.id.title_text_view_view_post_detail) TextView mTitleTextView;
@BindView(R.id.content_markdown_view_view_post_detail) MarkwonView mContentMarkdownView;
@BindView(R.id.type_text_view_view_post_detail) Chip mTypeChip;
@BindView(R.id.gilded_image_view_view_post_detail) ImageView mGildedImageView;
@BindView(R.id.gilded_number_text_view_view_post_detail) TextView mGildedNumberTextView;
@BindView(R.id.crosspost_image_view_view_post_detail) ImageView mCrosspostImageView;
@BindView(R.id.nsfw_text_view_view_post_detail) Chip mNSFWChip;
@BindView(R.id.link_text_view_view_post_detail) TextView linkTextView;
@BindView(R.id.image_view_wrapper_view_post_detail) RelativeLayout mRelativeLayout;
@BindView(R.id.load_wrapper_view_post_detail) RelativeLayout mLoadWrapper;
@BindView(R.id.progress_bar_view_post_detail) ProgressBar mLoadImageProgressBar;
@BindView(R.id.load_image_error_text_view_view_post_detail) TextView mLoadImageErrorTextView;
@BindView(R.id.image_view_view_post_detail) AspectRatioImageView mImageView;
@BindView(R.id.image_view_no_preview_link_view_post_detail) ImageView mNoPreviewLinkImageView;
@BindView(R.id.plus_button_view_post_detail) ImageView mUpvoteButton;
@BindView(R.id.score_text_view_view_post_detail) TextView mScoreTextView;
@BindView(R.id.minus_button_view_post_detail) ImageView mDownvoteButton;
@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) RecyclerView 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;
@Inject @Named("no_oauth") @Inject @Named("no_oauth")
Retrofit mRetrofit; Retrofit mRetrofit;
@ -148,14 +92,26 @@ public class ViewPostDetailActivity extends AppCompatActivity {
mGlide = Glide.with(this); mGlide = Glide.with(this);
mLocale = getResources().getConfiguration().locale; mLocale = getResources().getConfiguration().locale;
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
if(savedInstanceState == null) { if(savedInstanceState == null) {
orientation = getResources().getConfiguration().orientation; orientation = getResources().getConfiguration().orientation;
mPost = getIntent().getExtras().getParcelable(EXTRA_POST_DATA); mPost = getIntent().getExtras().getParcelable(EXTRA_POST_DATA);
} else { } else {
orientation = savedInstanceState.getInt(ORIENTATION_STATE); orientation = savedInstanceState.getInt(ORIENTATION_STATE);
mPost = savedInstanceState.getParcelable(POST_STATE); mPost = savedInstanceState.getParcelable(POST_STATE);
isRefreshing = savedInstanceState.getBoolean(IS_REFRESHING_STATE); }
mAdapter = new CommentRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit,
mOauthRetrofit, mGlide, mSharedPreferences, mPost,
mPost.getSubredditNamePrefixed(), mLocale, mLoadSubredditIconAsyncTask,
post -> EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)));
mRecyclerView.setAdapter(mAdapter);
if(savedInstanceState != null) {
isRefreshing = savedInstanceState.getBoolean(IS_REFRESHING_STATE);
if(isRefreshing) { if(isRefreshing) {
isRefreshing = false; isRefreshing = false;
refresh(); refresh();
@ -166,336 +122,11 @@ public class ViewPostDetailActivity extends AppCompatActivity {
postListPosition = getIntent().getExtras().getInt(EXTRA_POST_LIST_POSITION); postListPosition = getIntent().getExtras().getInt(EXTRA_POST_LIST_POSITION);
} }
mRecyclerView.setNestedScrollingEnabled(false);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
fetchComment(); fetchComment();
bindView();
initializeButtonOnClickListener();
}
private void bindView() {
mTitleTextView.setText(mPost.getTitle());
if(mPost.getSubredditIconUrl() == null) {
mLoadSubredditIconAsyncTask = new LoadSubredditIconAsyncTask(
SubredditRoomDatabase.getDatabase(this).subredditDao(), mPost.getSubredditNamePrefixed().substring(2),
iconImageUrl -> {
if(!iconImageUrl.equals("")) {
mGlide.load(iconImageUrl)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(mSubredditIconGifImageView);
} else {
mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(mSubredditIconGifImageView);
}
mPost.setSubredditIconUrl(iconImageUrl);
});
mLoadSubredditIconAsyncTask.execute();
} else if(!mPost.getSubredditIconUrl().equals("")) {
mGlide.load(mPost.getSubredditIconUrl())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(mSubredditIconGifImageView);
} else {
mGlide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(mSubredditIconGifImageView);
}
switch (mPost.getVoteType()) {
case 1:
//Upvote
mUpvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.backgroundColorPrimaryDark), PorterDuff.Mode.SRC_IN);
break;
case -1:
//Downvote
mDownvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.minusButtonColor), PorterDuff.Mode.SRC_IN);
break;
case 0:
mUpvoteButton.clearColorFilter();
mDownvoteButton.clearColorFilter();
}
if(mPost.getPostType() != Post.TEXT_TYPE && mPost.getPostType() != Post.NO_PREVIEW_LINK_TYPE) {
mRelativeLayout.setVisibility(View.VISIBLE);
mImageView.setVisibility(View.VISIBLE);
mImageView.setRatio((float) mPost.getPreviewHeight() / (float) mPost.getPreviewWidth());
loadImage();
} else {
mRelativeLayout.setVisibility(View.GONE);
mImageView.setVisibility(View.GONE);
}
if(mPost.isCrosspost()) {
mCrosspostImageView.setVisibility(View.VISIBLE);
}
mSubredditTextView.setText(mPost.getSubredditNamePrefixed());
mPostTimeTextView.setText(mPost.getPostTime());
if(mPost.getGilded() > 0) {
mGildedImageView.setVisibility(View.VISIBLE);
mGlide.load(R.drawable.gold).into(mGildedImageView);
mGildedNumberTextView.setVisibility(View.VISIBLE);
String gildedNumber = getResources().getString(R.string.gilded, mPost.getGilded());
mGildedNumberTextView.setText(gildedNumber);
}
if(mPost.isNSFW()) {
mNSFWChip.setVisibility(View.VISIBLE);
} else {
mNSFWChip.setVisibility(View.GONE);
}
String scoreWithVote = Integer.toString(mPost.getScore() + mPost.getVoteType());
mScoreTextView.setText(scoreWithVote);
switch (mPost.getPostType()) {
case Post.IMAGE_TYPE:
mTypeChip.setText("IMAGE");
mImageView.setOnClickListener(view -> {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewImageActivity.class);
intent.putExtra(ViewImageActivity.IMAGE_URL_KEY, mPost.getUrl());
intent.putExtra(ViewImageActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewImageActivity.FILE_NAME_KEY, mPost.getSubredditNamePrefixed().substring(2)
+ "-" + mPost.getId().substring(3));
startActivity(intent);
});
break;
case Post.LINK_TYPE:
mTypeChip.setText("LINK");
linkTextView.setVisibility(View.VISIBLE);
String domain = Uri.parse(mPost.getUrl()).getHost();
linkTextView.setText(domain);
mImageView.setOnClickListener(view -> {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
// add share action to menu list
builder.addDefaultShareMenuItem();
builder.setToolbarColor(getResources().getColor(R.color.colorPrimary));
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(ViewPostDetailActivity.this, Uri.parse(mPost.getUrl()));
});
break;
case Post.GIF_VIDEO_TYPE:
mTypeChip.setText("GIF");
final Uri gifVideoUri = Uri.parse(mPost.getVideoUrl());
mImageView.setOnClickListener(view -> {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewVideoActivity.class);
intent.setData(gifVideoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPost.isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPost.isDownloadableGifOrVideo());
if(mPost.isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPost.getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, mPost.getSubredditNamePrefixed());
intent.putExtra(ViewVideoActivity.ID_KEY, mPost.getId());
}
startActivity(intent);
});
break;
case Post.VIDEO_TYPE:
mTypeChip.setText("VIDEO");
final Uri videoUri = Uri.parse(mPost.getVideoUrl());
mImageView.setOnClickListener(view -> {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewVideoActivity.class);
intent.setData(videoUri);
intent.putExtra(ViewVideoActivity.TITLE_KEY, mPost.getTitle());
intent.putExtra(ViewVideoActivity.IS_DASH_VIDEO_KEY, mPost.isDashVideo());
intent.putExtra(ViewVideoActivity.IS_DOWNLOADABLE_KEY, mPost.isDownloadableGifOrVideo());
if(mPost.isDownloadableGifOrVideo()) {
intent.putExtra(ViewVideoActivity.DOWNLOAD_URL_KEY, mPost.getGifOrVideoDownloadUrl());
intent.putExtra(ViewVideoActivity.SUBREDDIT_KEY, mPost.getSubredditNamePrefixed());
intent.putExtra(ViewVideoActivity.ID_KEY, mPost.getId());
}
startActivity(intent);
});
break;
case Post.NO_PREVIEW_LINK_TYPE:
mTypeChip.setText("LINK");
linkTextView.setVisibility(View.VISIBLE);
String noPreviewLinkDomain = Uri.parse(mPost.getUrl()).getHost();
linkTextView.setText(noPreviewLinkDomain);
if(!mPost.getSelfText().equals("")) {
mContentMarkdownView.setVisibility(View.VISIBLE);
mContentMarkdownView.setMarkdown(getCustomSpannableConfiguration(), mPost.getSelfText());
}
mNoPreviewLinkImageView.setVisibility(View.VISIBLE);
mNoPreviewLinkImageView.setOnClickListener(view -> {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
// add share action to menu list
builder.addDefaultShareMenuItem();
builder.setToolbarColor(getResources().getColor(R.color.colorPrimary));
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(ViewPostDetailActivity.this, Uri.parse(mPost.getUrl()));
});
break;
case Post.TEXT_TYPE:
mTypeChip.setText("TEXT");
if(!mPost.getSelfText().equals("")) {
mContentMarkdownView.setVisibility(View.VISIBLE);
mContentMarkdownView.setMarkdown(getCustomSpannableConfiguration(), mPost.getSelfText());
}
break;
}
}
private void initializeButtonOnClickListener() {
mSubredditIconNameLinearLayout.setOnClickListener(view -> {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY,
mPost.getSubredditNamePrefixed().substring(2));
startActivity(intent);
});
mShareButton.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
String extraText = mPost.getTitle() + "\n" + mPost.getPermalink();
intent.putExtra(Intent.EXTRA_TEXT, extraText);
startActivity(Intent.createChooser(intent, "Share"));
});
mUpvoteButton.setOnClickListener(view -> {
ColorFilter previousUpvoteButtonColorFilter = mUpvoteButton.getColorFilter();
ColorFilter previousDownvoteButtonColorFilter = mDownvoteButton.getColorFilter();
int previousVoteType = mPost.getVoteType();
String newVoteType;
mDownvoteButton.clearColorFilter();
if(previousUpvoteButtonColorFilter == null) {
//Not upvoted before
mPost.setVoteType(1);
newVoteType = RedditUtils.DIR_UPVOTE;
mUpvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
//Upvoted before
mPost.setVoteType(0);
newVoteType = RedditUtils.DIR_UNVOTE;
mUpvoteButton.clearColorFilter();
}
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override
public void onVoteThingSuccess() {
if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) {
mPost.setVoteType(1);
mUpvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
mPost.setVoteType(0);
mUpvoteButton.clearColorFilter();
}
mDownvoteButton.clearColorFilter();
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
}
@Override
public void onVoteThingFail() {
Toast.makeText(ViewPostDetailActivity.this, R.string.vote_failed, Toast.LENGTH_SHORT).show();
mPost.setVoteType(previousVoteType);
mScoreTextView.setText(Integer.toString(mPost.getScore() + previousVoteType));
mUpvoteButton.setColorFilter(previousUpvoteButtonColorFilter);
mDownvoteButton.setColorFilter(previousDownvoteButtonColorFilter);
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
}
}, mPost.getFullName(), newVoteType);
});
mDownvoteButton.setOnClickListener(view -> {
ColorFilter previousUpvoteButtonColorFilter = mUpvoteButton.getColorFilter();
ColorFilter previousDownvoteButtonColorFilter = mDownvoteButton.getColorFilter();
int previousVoteType = mPost.getVoteType();
String newVoteType;
mUpvoteButton.clearColorFilter();
if(previousDownvoteButtonColorFilter == null) {
//Not upvoted before
mPost.setVoteType(-1);
newVoteType = RedditUtils.DIR_DOWNVOTE;
mDownvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
//Upvoted before
mPost.setVoteType(0);
newVoteType = RedditUtils.DIR_UNVOTE;
mDownvoteButton.clearColorFilter();
}
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingWithoutPositionListener() {
@Override
public void onVoteThingSuccess() {
if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) {
mPost.setVoteType(-1);
mDownvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN);
} else {
mPost.setVoteType(0);
mDownvoteButton.clearColorFilter();
}
mUpvoteButton.clearColorFilter();
mScoreTextView.setText(Integer.toString(mPost.getScore() + mPost.getVoteType()));
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
}
@Override
public void onVoteThingFail() {
Toast.makeText(ViewPostDetailActivity.this, R.string.vote_failed, Toast.LENGTH_SHORT).show();
mPost.setVoteType(previousVoteType);
mScoreTextView.setText(Integer.toString(mPost.getScore() + previousVoteType));
mUpvoteButton.setColorFilter(previousUpvoteButtonColorFilter);
mDownvoteButton.setColorFilter(previousDownvoteButtonColorFilter);
if(postListPosition != -1) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
}
}, mPost.getFullName(), newVoteType);
});
} }
private void fetchComment() { private void fetchComment() {
mCommentCardView.setVisibility(View.GONE); mAdapter.initiallyLoading();
mCommentProgressbar.setVisibility(View.VISIBLE);
mNoCommentWrapperLinearLayout.setVisibility(View.GONE);
FetchComment.fetchComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getId(), FetchComment.fetchComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getId(),
mLocale, new FetchComment.FetchCommentListener() { mLocale, new FetchComment.FetchCommentListener() {
@ -503,7 +134,19 @@ public class ViewPostDetailActivity extends AppCompatActivity {
public void onFetchCommentSuccess(ArrayList<CommentData> expandedComments, public void onFetchCommentSuccess(ArrayList<CommentData> expandedComments,
String parentId, ArrayList<String> children) { String parentId, ArrayList<String> children) {
ViewPostDetailActivity.this.children = children; ViewPostDetailActivity.this.children = children;
mCommentProgressbar.setVisibility(View.GONE);
mAdapter.addComments(expandedComments);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
/*mCommentProgressbar.setVisibility(View.GONE);
if (expandedComments.size() > 0) { if (expandedComments.size() > 0) {
if(mAdapter == null) { if(mAdapter == null) {
@ -520,26 +163,34 @@ public class ViewPostDetailActivity extends AppCompatActivity {
} }
mAdapter = new CommentRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, mAdapter = new CommentRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit,
mOauthRetrofit, mSharedPreferences, expandedComments, mOauthRetrofit, mGlide, mSharedPreferences, mPost,
mPost.getSubredditNamePrefixed(), mLocale); mPost.getSubredditNamePrefixed(), mLocale, new CommentRecyclerViewAdapter.UpdatePostInPostFragmentCallback() {
@Override
public void updatePost(Post post) {
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
}
});
mRecyclerView.setAdapter(mAdapter); mRecyclerView.setAdapter(mAdapter);
mCommentCardView.setVisibility(View.VISIBLE); //mCommentCardView.setVisibility(View.VISIBLE);
} else { } else {
mNoCommentWrapperLinearLayout.setVisibility(View.VISIBLE); mNoCommentWrapperLinearLayout.setVisibility(View.VISIBLE);
mGlide.load(R.drawable.no_comment_indicator).into(mNoCommentImageView); mGlide.load(R.drawable.no_comment_placeholder).into(mNoCommentImageView);
} }*/
} }
@Override @Override
public void onFetchCommentFailed() { public void onFetchCommentFailed() {
mCommentProgressbar.setVisibility(View.GONE); mAdapter.initiallyLoadCommentsFailed();
showRetrySnackbar();
} }
}); });
} }
private void fetchMoreComment(int startingIndex) { private void fetchMoreComment(int startingIndex) {
if(isLoadingMoreChildren) {
return;
}
isLoadingMoreChildren = true; isLoadingMoreChildren = true;
FetchComment.fetchMoreComment(mRetrofit, mPost.getSubredditNamePrefixed(), children, startingIndex, FetchComment.fetchMoreComment(mRetrofit, mPost.getSubredditNamePrefixed(), children, startingIndex,
0, mLocale, new FetchComment.FetchMoreCommentListener() { 0, mLocale, new FetchComment.FetchMoreCommentListener() {
@ -560,73 +211,11 @@ public class ViewPostDetailActivity extends AppCompatActivity {
}); });
} }
private void loadImage() {
RequestBuilder imageRequestBuilder = mGlide.load(mPost.getPreviewUrl())
.apply(new RequestOptions().override(mPost.getPreviewWidth(), mPost.getPreviewHeight()))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
mLoadImageProgressBar.setVisibility(View.GONE);
mLoadImageErrorTextView.setVisibility(View.VISIBLE);
mLoadImageErrorTextView.setOnClickListener(view -> {
mLoadImageProgressBar.setVisibility(View.VISIBLE);
mLoadImageErrorTextView.setVisibility(View.GONE);
loadImage();
});
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
mLoadWrapper.setVisibility(View.GONE);
return false;
}
});
if(mPost.isNSFW()) {
imageRequestBuilder.apply(RequestOptions.bitmapTransform(new BlurTransformation(50, 2)))
.into(mImageView);
} else {
imageRequestBuilder.into(mImageView);
}
}
private SpannableConfiguration getCustomSpannableConfiguration() {
return SpannableConfiguration.builder(this).linkResolver((view, link) -> {
if(link.startsWith("/u/") || link.startsWith("u/")) {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3));
startActivity(intent);
} else if(link.startsWith("/r/") || link.startsWith("r/")) {
Intent intent = new Intent(ViewPostDetailActivity.this, ViewSubredditDetailActivity.class);
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3));
startActivity(intent);
} else {
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
// add share action to menu list
builder.addDefaultShareMenuItem();
builder.setToolbarColor(getResources().getColor(R.color.colorPrimary));
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(ViewPostDetailActivity.this, Uri.parse(link));
}
}).build();
}
private void showRetrySnackbar() {
Snackbar snackbar = Snackbar.make(mCoordinatorLayout, R.string.post_load_comments_failed, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.retry, view -> fetchComment());
snackbar.show();
}
private void refresh() { private void refresh() {
if(!isRefreshing) { if(!isRefreshing) {
isRefreshing = true; isRefreshing = true;
mChildrenStartingIndex = 0; mChildrenStartingIndex = 0;
if(mAdapter != null) {
mAdapter.clearData();
}
fetchComment(); fetchComment();
String accessToken = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) String accessToken = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE)
@ -636,7 +225,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
@Override @Override
public void fetchPostSuccess(Post post) { public void fetchPostSuccess(Post post) {
mPost = post; mPost = post;
bindView(); mAdapter.updatePost(mPost);
EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition));
isRefreshing = false; isRefreshing = false;
} }
@ -654,7 +243,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
public void onPostUpdateEvent(PostUpdateEventToDetailActivity event) { public void onPostUpdateEvent(PostUpdateEventToDetailActivity event) {
if(mPost.getId().equals(event.postId)) { if(mPost.getId().equals(event.postId)) {
mPost.setVoteType(event.voteType); mPost.setVoteType(event.voteType);
mScoreTextView.setText(Integer.toString(mPost.getScore() + event.voteType)); mAdapter.updatePost(mPost);
} }
} }

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -21,339 +21,10 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/nested_scroll_view_view_post_detail_activity" android:id="@+id/recycler_view_view_post_detail"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:descendantFocusability="blocksDescendants">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/relative_layout_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/subreddit_icon_name_linear_layout_view_post_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/post_time_text_view_view_post_detail"
app:layout_constraintTop_toTopOf="parent">
<CustomView.AspectRatioGifImageView
android:id="@+id/subreddit_icon_circle_image_view_view_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"/>
<TextView
android:id="@+id/subreddit_text_view_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_gravity="center"
android:textColor="#E91E63" />
</LinearLayout>
<TextView
android:id="@+id/post_time_text_view_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/subreddit_icon_name_linear_layout_view_post_detail"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/title_text_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="@color/primaryTextColor"
android:textSize="18sp" />
<ru.noties.markwon.view.MarkwonView
android:id="@+id/content_markdown_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginTop="16dp"
android:visibility="gone" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="16dp">
<com.google.android.material.chip.Chip
android:id="@+id/type_text_view_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:textColor="@android:color/white"
android:layout_centerVertical="true"
app:chipBackgroundColor="@color/backgroundColorPrimaryDark"/>
<ImageView
android:id="@+id/gilded_image_view_view_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_toEndOf="@id/type_text_view_view_post_detail"
android:layout_centerVertical="true"
android:visibility="gone"/>
<TextView
android:id="@+id/gilded_number_text_view_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/gilded_image_view_view_post_detail"
android:layout_centerVertical="true"
android:visibility="gone"
android:textSize="20sp"
android:textColor="@color/gold"/>
<ImageView
android:id="@+id/crosspost_image_view_view_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/gilded_number_text_view_view_post_detail"
android:layout_centerVertical="true"
android:src="@drawable/crosspost"
android:tint="@color/colorAccent"
android:visibility="gone"/>
<com.google.android.material.chip.Chip
android:id="@+id/nsfw_text_view_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nsfw"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:textColor="@android:color/white"
android:visibility="gone"
android:layout_centerVertical="true"
app:chipBackgroundColor="@color/colorAccent"/>
</RelativeLayout>
<TextView
android:id="@+id/link_text_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textSize="12sp"
android:visibility="gone"/>
<RelativeLayout
android:id="@+id/image_view_wrapper_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone">
<com.santalu.aspectratioimageview.AspectRatioImageView
android:id="@+id/image_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitStart"/>
<RelativeLayout
android:id="@+id/load_wrapper_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/progress_bar_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/load_image_error_text_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_error_outline_black_24dp"
android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/tap_to_retry"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
<ImageView
android:id="@+id/image_view_no_preview_link_view_post_detail"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="16dp"
android:background="@color/grey"
android:scaleType="center"
android:src="@drawable/ic_link"
android:tint="@android:color/tab_indicator_text"
android:visibility="gone" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/plus_button_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_arrow_upward_black_24dp"
android:tint="@android:color/tab_indicator_text" />
<TextView
android:id="@+id/score_text_view_view_post_detail"
android:layout_width="64dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/plus_button_view_post_detail"
android:gravity="center" />
<ImageView
android:id="@+id/minus_button_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/score_text_view_view_post_detail"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_arrow_downward_black_24dp"
android:tint="@android:color/tab_indicator_text" />
<ImageView
android:id="@+id/share_button_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_outline_share_24px"
android:tint="@android:color/tab_indicator_text" />
</RelativeLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar
android:id="@+id/comment_progress_bar_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:mlpb_progress_stoke_width="3dp"
app:mlpb_progress_color="@color/colorAccent"
app:mlpb_background_color="@color/circularProgressBarBackground"
android:layout_gravity="center_horizontal"/>
<com.google.android.material.card.MaterialCardView
android:id="@+id/comment_card_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingStart="16dp"
android:paddingTop="16dp"
android:text="@string/comments"
android:textColor="@color/primaryTextColor"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:id="@+id/no_comment_wrapper_linear_layout_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="@+id/no_comment_image_view_view_post_detail"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:text="@string/no_comments_yet"/>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar
android:id="@+id/comment_progress_bar_view_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:mlpb_progress_stoke_width="3dp"
app:mlpb_progress_color="@color/colorAccent"
app:mlpb_background_color="@color/circularProgressBarBackground"
android:layout_gravity="center_horizontal"/>
</LinearLayout>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="36dp"
android:text="@string/post_load_comments_failed"
android:drawableTop="@drawable/load_post_error_indicator"/>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/no_comments_yet"
android:gravity="center"
android:padding="36dp"
android:drawableTop="@drawable/no_comment_placeholder"/>

View File

@ -0,0 +1,252 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/relative_layout_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/subreddit_icon_name_linear_layout_item_post_detail"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/post_time_text_view_item_post_detail"
app:layout_constraintTop_toTopOf="parent">
<CustomView.AspectRatioGifImageView
android:id="@+id/subreddit_icon_circle_image_view_item_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"/>
<TextView
android:id="@+id/subreddit_text_view_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_gravity="center"
android:textColor="#E91E63" />
</LinearLayout>
<TextView
android:id="@+id/post_time_text_view_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/subreddit_icon_name_linear_layout_item_post_detail"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/title_text_view_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textColor="@color/primaryTextColor"
android:textSize="18sp" />
<ru.noties.markwon.view.MarkwonView
android:id="@+id/content_markdown_view_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_marginTop="16dp"
android:visibility="gone" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingTop="16dp">
<com.google.android.material.chip.Chip
android:id="@+id/type_text_view_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:textColor="@android:color/white"
android:layout_centerVertical="true"
app:chipBackgroundColor="@color/backgroundColorPrimaryDark"/>
<ImageView
android:id="@+id/gilded_image_view_item_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_toEndOf="@id/type_text_view_item_post_detail"
android:layout_centerVertical="true"
android:visibility="gone"/>
<TextView
android:id="@+id/gilded_number_text_view_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/gilded_image_view_item_post_detail"
android:layout_centerVertical="true"
android:visibility="gone"
android:textSize="20sp"
android:textColor="@color/gold"/>
<ImageView
android:id="@+id/crosspost_image_view_item_post_detail"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_toEndOf="@id/gilded_number_text_view_item_post_detail"
android:layout_centerVertical="true"
android:src="@drawable/crosspost"
android:tint="@color/colorAccent"
android:visibility="gone"/>
<com.google.android.material.chip.Chip
android:id="@+id/nsfw_text_view_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nsfw"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:textColor="@android:color/white"
android:visibility="gone"
android:layout_centerVertical="true"
app:chipBackgroundColor="@color/colorAccent"/>
</RelativeLayout>
<TextView
android:id="@+id/link_text_view_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:textSize="12sp"
android:visibility="gone"/>
<RelativeLayout
android:id="@+id/image_view_wrapper_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone">
<com.santalu.aspectratioimageview.AspectRatioImageView
android:id="@+id/image_view_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitStart"/>
<RelativeLayout
android:id="@+id/load_wrapper_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<ProgressBar
android:id="@+id/progress_bar_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
<TextView
android:id="@+id/load_image_error_text_view_item_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_error_outline_black_24dp"
android:layout_centerInParent="true"
android:gravity="center"
android:text="@string/tap_to_retry"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
<ImageView
android:id="@+id/image_view_no_preview_link_item_post_detail"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_marginTop="16dp"
android:background="@color/grey"
android:scaleType="center"
android:src="@drawable/ic_link"
android:tint="@android:color/tab_indicator_text"
android:visibility="gone" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/plus_button_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_arrow_upward_black_24dp"
android:tint="@android:color/tab_indicator_text" />
<TextView
android:id="@+id/score_text_view_item_post_detail"
android:layout_width="64dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/plus_button_item_post_detail"
android:gravity="center" />
<ImageView
android:id="@+id/minus_button_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/score_text_view_item_post_detail"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_arrow_downward_black_24dp"
android:tint="@android:color/tab_indicator_text" />
<ImageView
android:id="@+id/share_button_item_post_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="?actionBarItemBackground"
android:clickable="true"
android:focusable="true"
android:padding="16dp"
android:src="@drawable/ic_outline_share_24px"
android:tint="@android:color/tab_indicator_text" />
</RelativeLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>