From 611d6a90ec39707b4d4161da1eb5b19249e670c4 Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Thu, 18 Jul 2019 12:00:46 +0800 Subject: Viewing rules after pressing rules button in PostXXXActivity is available. Extend MarkwonView to support opening reddit subreddit and user links. --- .../main/java/CustomView/CustomMarkwonView.java | 49 + .../infinityforreddit/AppComponent.java | 1 + .../CommentAndPostRecyclerViewAdapter.java | 1144 +++++++++++++++++++ .../CommentRecyclerViewAdapter.java | 1185 -------------------- .../infinityforreddit/JSONUtils.java | 3 + .../infinityforreddit/PostImageActivity.java | 14 + .../infinityforreddit/PostLinkActivity.java | 14 + .../infinityforreddit/PostTextActivity.java | 14 + .../infinityforreddit/PostVideoActivity.java | 14 + .../infinityforreddit/RedditAPI.java | 3 + .../ml/docilealligator/infinityforreddit/Rule.java | 19 + .../infinityforreddit/RulesActivity.java | 170 +++ .../RulesRecyclerViewAdapter.java | 67 ++ .../infinityforreddit/ViewPostDetailActivity.java | 6 +- .../ViewSubredditDetailActivity.java | 2 +- .../infinityforreddit/ViewUserDetailActivity.java | 2 +- 16 files changed, 1517 insertions(+), 1190 deletions(-) create mode 100644 app/src/main/java/CustomView/CustomMarkwonView.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java delete mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/Rule.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/RulesActivity.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/RulesRecyclerViewAdapter.java (limited to 'app/src/main/java') diff --git a/app/src/main/java/CustomView/CustomMarkwonView.java b/app/src/main/java/CustomView/CustomMarkwonView.java new file mode 100644 index 00000000..c0d59f05 --- /dev/null +++ b/app/src/main/java/CustomView/CustomMarkwonView.java @@ -0,0 +1,49 @@ +package CustomView; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.util.AttributeSet; + +import androidx.annotation.Nullable; +import androidx.browser.customtabs.CustomTabsIntent; + +import ml.docilealligator.infinityforreddit.R; +import ml.docilealligator.infinityforreddit.ViewSubredditDetailActivity; +import ml.docilealligator.infinityforreddit.ViewUserDetailActivity; +import ru.noties.markwon.SpannableConfiguration; +import ru.noties.markwon.view.MarkwonView; + +public class CustomMarkwonView extends MarkwonView { + + public CustomMarkwonView(Context context) { + super(context); + } + + public CustomMarkwonView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setMarkdown(@Nullable String markdown, Context conte) { + SpannableConfiguration configuration = SpannableConfiguration.builder(conte).linkResolver((view, link) -> { + if(link.startsWith("/u/") || link.startsWith("u/")) { + Intent intent = new Intent(conte, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3)); + conte.startActivity(intent); + } else if(link.startsWith("/r/") || link.startsWith("r/")) { + Intent intent = new Intent(conte, ViewSubredditDetailActivity.class); + intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3)); + conte.startActivity(intent); + } else { + CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); + // add share action to menu list + builder.addDefaultShareMenuItem(); + builder.setToolbarColor(conte.getResources().getColor(R.color.colorPrimary)); + CustomTabsIntent customTabsIntent = builder.build(); + customTabsIntent.launchUrl(conte, Uri.parse(link)); + } + }).build(); + + super.setMarkdown(configuration, markdown); + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java index da7da984..87c4f254 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java @@ -23,4 +23,5 @@ interface AppComponent { void inject(PostImageActivity postImageActivity); void inject(PostVideoActivity postVideoActivity); void inject(FlairBottomSheetFragment flairBottomSheetFragment); + void inject(RulesActivity rulesActivity); } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java new file mode 100644 index 00000000..3bb3ef10 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentAndPostRecyclerViewAdapter.java @@ -0,0 +1,1144 @@ +package ml.docilealligator.infinityforreddit; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.ColorFilter; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.browser.customtabs.CustomTabsIntent; +import androidx.core.content.ContextCompat; +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.libRG.CustomTextView; +import com.santalu.aspectratioimageview.AspectRatioImageView; + +import java.util.ArrayList; +import java.util.Locale; + +import CustomView.AspectRatioGifImageView; +import CustomView.CustomMarkwonView; +import SubredditDatabase.SubredditRoomDatabase; +import User.UserRoomDatabase; +import butterknife.BindView; +import butterknife.ButterKnife; +import jp.wasabeef.glide.transformations.BlurTransformation; +import jp.wasabeef.glide.transformations.RoundedCornersTransformation; +import retrofit2.Retrofit; + +class CommentAndPostRecyclerViewAdapter extends RecyclerView.Adapter { + private static final int VIEW_TYPE_POST_DETAIL = 0; + 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_CHILD_COMMENTS = 5; + private static final int VIEW_TYPE_IS_LOADING_MORE_COMMENTS = 6; + private static final int VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED = 7; + + private Activity mActivity; + private Retrofit mRetrofit; + private Retrofit mOauthRetrofit; + private RequestManager mGlide; + private SharedPreferences mSharedPreferences; + private Post mPost; + private ArrayList mVisibleComments; + private String mSubredditNamePrefixed; + private Locale mLocale; + private CommentRecyclerViewAdapterCallback mCommentRecyclerViewAdapterCallback; + private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; + private boolean isInitiallyLoading; + private boolean isInitiallyLoadingFailed; + private boolean mHasMoreComments; + private boolean loadMoreCommentsFailed; + + interface CommentRecyclerViewAdapterCallback { + void updatePost(Post post); + void retryFetchingMoreComments(); + } + + CommentAndPostRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, RequestManager glide, + SharedPreferences sharedPreferences, Post post, String subredditNamePrefixed, + Locale locale, LoadSubredditIconAsyncTask loadSubredditIconAsyncTask, + CommentRecyclerViewAdapterCallback commentRecyclerViewAdapterCallback) { + mActivity = activity; + mRetrofit = retrofit; + mOauthRetrofit = oauthRetrofit; + mGlide = glide; + mSharedPreferences = sharedPreferences; + mPost = post; + mVisibleComments = new ArrayList<>(); + mSubredditNamePrefixed = subredditNamePrefixed; + mLocale = locale; + mLoadSubredditIconAsyncTask = loadSubredditIconAsyncTask; + mCommentRecyclerViewAdapterCallback = commentRecyclerViewAdapterCallback; + isInitiallyLoading = true; + isInitiallyLoadingFailed = false; + mHasMoreComments = false; + loadMoreCommentsFailed = false; + } + + @Override + public int getItemViewType(int 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; + } + } + } + + if(position == mVisibleComments.size() + 1) { + if(mHasMoreComments) { + return VIEW_TYPE_IS_LOADING_MORE_COMMENTS; + } else { + return VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED; + } + } + + CommentData comment = mVisibleComments.get(position - 1); + if(!comment.isPlaceHolder()) { + return VIEW_TYPE_COMMENT; + } else { + return VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS; + } + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + switch (viewType) { + case VIEW_TYPE_POST_DETAIL: + return new PostDetailViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail, parent, false)); + case VIEW_TYPE_FIRST_LOADING: + return new LoadCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments, parent, false)); + case VIEW_TYPE_FIRST_LOADING_FAILED: + return new LoadCommentsFailedViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments_failed_placeholder, parent, false)); + case VIEW_TYPE_NO_COMMENT_PLACEHOLDER: + return new NoCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_no_comment_placeholder, parent, false)); + case VIEW_TYPE_COMMENT: + return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false)); + case VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS: + return new LoadMoreChildCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_comments_placeholder, parent, false)); + case VIEW_TYPE_IS_LOADING_MORE_COMMENTS: + return new IsLoadingMoreCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment_footer_loading, parent, false)); + default: + return new LoadMoreCommentsFailedViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment_footer_error, parent, false)); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(holder.getItemViewType() == VIEW_TYPE_POST_DETAIL) { + ((PostDetailViewHolder) holder).mTitleTextView.setText(mPost.getTitle()); + + if(mPost.getSubredditNamePrefixed().equals("u/" + mPost.getAuthor())) { + if(mPost.getAuthorIconUrl() == null) { + new LoadUserDataAsyncTask(UserRoomDatabase.getDatabase(mActivity).userDao(), mPost.getAuthor(), mOauthRetrofit, iconImageUrl -> { + if(mActivity != null && getItemCount() > 0) { + 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); + } + + if(holder.getAdapterPosition() >= 0) { + mPost.setAuthorIconUrl(iconImageUrl); + } + } + }).execute(); + } else if(!mPost.getAuthorIconUrl().equals("")) { + mGlide.load(mPost.getAuthorIconUrl()) + .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); + } + } else { + if(mPost.getSubredditIconUrl() == null) { + if(mLoadSubredditIconAsyncTask != null) { + mLoadSubredditIconAsyncTask.cancel(true); + } + 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.isSpoiler() || mPost.getFlair() != null) { + ((PostDetailViewHolder) holder).spoilerFlairlinearLayout.setVisibility(View.VISIBLE); + } + + if(mPost.isSpoiler()) { + ((PostDetailViewHolder) holder).spoilerTextView.setVisibility(View.VISIBLE); + ((PostDetailViewHolder) holder).spoilerTextView + .setBackgroundColor(mActivity.getResources().getColor(R.color.backgroundColorPrimaryDark)); + } + + if(mPost.getFlair() != null) { + ((PostDetailViewHolder) holder).flairTextView.setVisibility(View.VISIBLE); + ((PostDetailViewHolder) holder).flairTextView.setText(mPost.getFlair()); + ((PostDetailViewHolder) holder).flairTextView + .setBackgroundColor(mActivity.getResources().getColor(R.color.backgroundColorPrimaryDark)); + } + + 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(mPost.getSelfText(), mActivity); + } + ((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(mPost.getSelfText(), mActivity); + } + break; + } + } else if(holder.getItemViewType() == VIEW_TYPE_COMMENT) { + CommentData comment = mVisibleComments.get(holder.getAdapterPosition() - 1); + + String authorPrefixed = "u/" + comment.getAuthor(); + ((CommentViewHolder) holder).authorTextView.setText(authorPrefixed); + + ((CommentViewHolder) holder).commentTimeTextView.setText(comment.getCommentTime()); + + ((CommentViewHolder) holder).commentMarkdownView.setMarkdown(comment.getCommentContent(), mActivity); + ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(comment.getScore())); + + ViewGroup.LayoutParams params = ((CommentViewHolder) holder).verticalBlock.getLayoutParams(); + params.width = comment.getDepth() * 16; + ((CommentViewHolder) holder).verticalBlock.setLayoutParams(params); + + if (comment.hasReply()) { + if(comment.isExpanded()) { + ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); + } else { + ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); + } + ((CommentViewHolder) holder).expandButton.setVisibility(View.VISIBLE); + } + + switch (comment.getVoteType()) { + case 1: + ((CommentViewHolder) holder).upvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + break; + case 2: + ((CommentViewHolder) holder).downvoteButton + .setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + break; + } + } else if(holder instanceof LoadMoreChildCommentsViewHolder) { + CommentData placeholder; + placeholder = mVisibleComments.get(holder.getAdapterPosition() - 1); + + ViewGroup.LayoutParams params = ((LoadMoreChildCommentsViewHolder) holder).verticalBlock.getLayoutParams(); + params.width = placeholder.getDepth() * 16; + ((LoadMoreChildCommentsViewHolder) holder).verticalBlock.setLayoutParams(params); + + if(placeholder.isLoadingMoreChildren()) { + ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.loading); + } else if(placeholder.isLoadMoreChildrenFailed()) { + ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments_failed); + } else { + ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments); + } + } else if(holder instanceof LoadMoreCommentsFailedViewHolder) { + ((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.post_load_comments_failed); + } + } + + private void loadImage(PostDetailViewHolder holder) { + RequestBuilder imageRequestBuilder = mGlide.load(mPost.getPreviewUrl()) + .apply(new RequestOptions().override(mPost.getPreviewWidth(), mPost.getPreviewHeight())) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target 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 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); + } + } + + void updatePost(Post post) { + mPost = post; + notifyItemChanged(0); + } + + private int getParentPosition(int position) { + int childDepth = mVisibleComments.get(position).getDepth(); + for(int i = position; i >= 0; i--) { + if(mVisibleComments.get(i).getDepth() < childDepth) { + return i; + } + } + return -1; + } + + private void expandChildren(int position) { + CommentData comment = mVisibleComments.get(position); + if(!comment.isExpanded()) { + comment.setExpanded(true); + ArrayList children = comment.getChildren(); + if(children != null && children.size() > 0) { + for(int i = 0; i < children.size(); i++) { + children.get(i).setExpanded(false); + } + mVisibleComments.addAll(position + 1, children); + notifyItemRangeInserted(position + 2, children.size()); + } + } + } + + private void collapseChildren(int position) { + mVisibleComments.get(position).setExpanded(false); + int depth = mVisibleComments.get(position).getDepth(); + int allChildrenSize = 0; + for(int i = position + 1; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getDepth() > depth) { + allChildrenSize++; + } else { + break; + } + } + + mVisibleComments.subList(position + 1, position + 1 + allChildrenSize).clear(); + notifyItemRangeRemoved(position + 2, allChildrenSize); + } + + void addComments(ArrayList comments, boolean hasMoreComments) { + if(mVisibleComments.size() == 0) { + isInitiallyLoading = false; + isInitiallyLoadingFailed = false; + if(comments.size() == 0) { + notifyItemChanged(1); + } else { + notifyItemRemoved(1); + } + } + + int sizeBefore = mVisibleComments.size(); + mVisibleComments.addAll(comments); + notifyItemRangeInserted(sizeBefore + 1, comments.size()); + + if(mHasMoreComments != hasMoreComments) { + if(hasMoreComments) { + notifyItemInserted(mVisibleComments.size() + 1); + } else { + notifyItemRemoved(mVisibleComments.size() + 1); + } + } + mHasMoreComments = hasMoreComments; + } + + void addComment(CommentData comment) { + if(mVisibleComments.size() == 0 || isInitiallyLoadingFailed) { + notifyItemRemoved(1); + } + + mVisibleComments.add(0, comment); + + if(isInitiallyLoading) { + notifyItemInserted(2); + } else { + notifyItemInserted(1); + } + } + + void addChildComment(CommentData comment, String parentFullname, int parentPosition) { + if(!parentFullname.equals(mVisibleComments.get(parentPosition).getFullName())) { + for(int i = 0; i < mVisibleComments.size(); i++) { + if(parentFullname.equals(mVisibleComments.get(i).getFullName())) { + parentPosition = i; + break; + } + } + } + + mVisibleComments.get(parentPosition).addChild(comment); + mVisibleComments.get(parentPosition).setHasReply(true); + if(!mVisibleComments.get(parentPosition).isExpanded()) { + expandChildren(parentPosition); + notifyItemChanged(parentPosition + 1); + } else { + mVisibleComments.add(parentPosition + 1, comment); + notifyItemInserted(parentPosition + 2); + } + } + + void initiallyLoading() { + if(mLoadSubredditIconAsyncTask != null) { + mLoadSubredditIconAsyncTask.cancel(true); + } + + if(mVisibleComments.size() != 0) { + int previousSize = mVisibleComments.size(); + mVisibleComments.clear(); + notifyItemRangeRemoved(1, previousSize); + } + + if(isInitiallyLoading || isInitiallyLoadingFailed || mVisibleComments.size() == 0) { + isInitiallyLoading = true; + isInitiallyLoadingFailed = false; + notifyItemChanged(1); + } else { + isInitiallyLoading = true; + isInitiallyLoadingFailed = false; + notifyItemInserted(1); + } + } + + void initiallyLoadCommentsFailed() { + isInitiallyLoading = false; + isInitiallyLoadingFailed = true; + notifyItemChanged(1); + } + + void loadMoreCommentsFailed() { + loadMoreCommentsFailed = true; + notifyItemChanged(mVisibleComments.size() + 1); + } + + ArrayList getVisibleComments() { + return mVisibleComments; + } + + @Override + public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { + if (holder instanceof CommentViewHolder) { + ((CommentViewHolder) holder).expandButton.setVisibility(View.GONE); + ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); + ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); + } + } + + @Override + public int getItemCount() { + if(isInitiallyLoading || isInitiallyLoadingFailed || mVisibleComments.size() == 0) { + return 2; + } + + if(mHasMoreComments || loadMoreCommentsFailed) { + return mVisibleComments.size() + 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_gif_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) CustomMarkwonView 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.spoiler_flair_linear_layout_item_post_detail) LinearLayout spoilerFlairlinearLayout; + @BindView(R.id.spoiler_custom_text_view_item_post_detail) CustomTextView spoilerTextView; + @BindView(R.id.flair_custom_text_view_item_post_detail) CustomTextView flairTextView; + @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; + + PostDetailViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + mSubredditIconNameLinearLayout.setOnClickListener(view -> { + Intent intent; + if(mPost.getSubredditNamePrefixed().equals("u/" + mPost.getAuthor())) { + intent = new Intent(mActivity, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mPost.getAuthor()); + } else { + 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())); + + mCommentRecyclerViewAdapterCallback.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())); + + mCommentRecyclerViewAdapterCallback.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); + + mCommentRecyclerViewAdapterCallback.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())); + + mCommentRecyclerViewAdapterCallback.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())); + + mCommentRecyclerViewAdapterCallback.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); + + mCommentRecyclerViewAdapterCallback.updatePost(mPost); + } + }, mPost.getFullName(), newVoteType); + }); + } + } + + class CommentViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.author_text_view_item_post_comment) TextView authorTextView; + @BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView; + @BindView(R.id.comment_markdown_view_item_post_comment) CustomMarkwonView commentMarkdownView; + @BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton; + @BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView; + @BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton; + @BindView(R.id.expand_button_item_post_comment) ImageView expandButton; + @BindView(R.id.share_button_item_post_comment) ImageView shareButton; + @BindView(R.id.reply_button_item_post_comment) ImageView replyButton; + @BindView(R.id.vertical_block_item_post_comment) View verticalBlock; + + CommentViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + authorTextView.setOnClickListener(view -> { + Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getAuthor()); + mActivity.startActivity(intent); + }); + + shareButton.setOnClickListener(view -> { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + String extraText = mVisibleComments.get(getAdapterPosition() - 1).getPermalink(); + intent.putExtra(Intent.EXTRA_TEXT, extraText); + mActivity.startActivity(Intent.createChooser(intent, "Share")); + }); + + expandButton.setOnClickListener(view -> { + if(mVisibleComments.get(getAdapterPosition() - 1).isExpanded()) { + collapseChildren(getAdapterPosition() - 1); + expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); + } else { + expandChildren(getAdapterPosition() - 1); + mVisibleComments.get(getAdapterPosition() - 1).setExpanded(true); + expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); + } + }); + + replyButton.setOnClickListener(view -> { + Intent intent = new Intent(mActivity, CommentActivity.class); + intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, mVisibleComments.get(getAdapterPosition() - 1).getDepth() + 1); + intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, mVisibleComments.get(getAdapterPosition() - 1).getCommentContent()); + intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getFullName()); + intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true); + intent.putExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, getAdapterPosition() - 1); + mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE); + }); + + upvoteButton.setOnClickListener(view -> { + int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType(); + String newVoteType; + + downvoteButton.clearColorFilter(); + + if(previousVoteType != CommentData.VOTE_TYPE_UPVOTE) { + //Not upvoted before + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE); + newVoteType = RedditUtils.DIR_UPVOTE; + upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + //Upvoted before + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); + newVoteType = RedditUtils.DIR_UNVOTE; + upvoteButton.clearColorFilter(); + } + + scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); + + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position) { + if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) { + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE); + upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); + upvoteButton.clearColorFilter(); + } + + downvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); + } + + @Override + public void onVoteThingFail(int position) { } + }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition()); + }); + + downvoteButton.setOnClickListener(view -> { + int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType(); + String newVoteType; + + upvoteButton.clearColorFilter(); + + if(previousVoteType != CommentData.VOTE_TYPE_DOWNVOTE) { + //Not downvoted before + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); + newVoteType = RedditUtils.DIR_DOWNVOTE; + downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + //Downvoted before + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); + newVoteType = RedditUtils.DIR_UNVOTE; + downvoteButton.clearColorFilter(); + } + + scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); + + VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { + @Override + public void onVoteThingSuccess(int position1) { + if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) { + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); + downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); + } else { + mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); + downvoteButton.clearColorFilter(); + } + + upvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); + } + + @Override + public void onVoteThingFail(int position1) { } + }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition()); + }); + } + } + + class LoadMoreChildCommentsViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.vertical_block_item_load_more_comments) View verticalBlock; + @BindView(R.id.placeholder_text_view_item_load_more_comments) TextView placeholderTextView; + + LoadMoreChildCommentsViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + placeholderTextView.setOnClickListener(view -> { + int parentPosition = getParentPosition(getAdapterPosition() - 1); + CommentData parentComment = mVisibleComments.get(parentPosition); + + mVisibleComments.get(getAdapterPosition() - 1).setLoadingMoreChildren(true); + mVisibleComments.get(getAdapterPosition() - 1).setLoadMoreChildrenFailed(false); + placeholderTextView.setText(R.string.loading); + + FetchComment.fetchMoreComment(mRetrofit, mSubredditNamePrefixed, parentComment.getMoreChildrenFullnames(), + parentComment.getMoreChildrenStartingIndex(), parentComment.getDepth() + 1, mLocale, + new FetchComment.FetchMoreCommentListener() { + @Override + public void onFetchMoreCommentSuccess(ArrayList expandedComments, + int childrenStartingIndex) { + if(mVisibleComments.size() > parentPosition + && parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) { + if(mVisibleComments.get(parentPosition).isExpanded()) { + if(mVisibleComments.get(parentPosition).getChildren().size() > childrenStartingIndex) { + mVisibleComments.get(parentPosition).setMoreChildrenStartingIndex(childrenStartingIndex); + mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) + .setLoadingMoreChildren(false); + mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) + .setLoadMoreChildrenFailed(false); + + int placeholderPosition = getAdapterPosition() - 1; + if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { + for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { + placeholderPosition = i; + break; + } + } + } + + mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); + mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(false); + placeholderTextView.setText(R.string.comment_load_more_comments); + + mVisibleComments.addAll(placeholderPosition, expandedComments); + notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); + } else { + mVisibleComments.get(parentPosition).getChildren() + .remove(mVisibleComments.get(parentPosition).getChildren().size() - 1); + mVisibleComments.get(parentPosition).removeMoreChildrenFullnames(); + + int placeholderPosition = getAdapterPosition() - 1; + if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { + for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { + placeholderPosition = i; + break; + } + } + } + + mVisibleComments.remove(placeholderPosition); + notifyItemRemoved(placeholderPosition + 1); + + mVisibleComments.addAll(placeholderPosition, expandedComments); + notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); + } + } else { + if(mVisibleComments.get(parentPosition).hasReply() && mVisibleComments.get(parentPosition).getChildren().size() <= childrenStartingIndex) { + mVisibleComments.get(parentPosition).getChildren() + .remove(mVisibleComments.get(parentPosition).getChildren().size() - 1); + mVisibleComments.get(parentPosition).removeMoreChildrenFullnames(); + } + } + + mVisibleComments.get(parentPosition).addChildren(expandedComments); + } else { + for(int i = 0; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { + if(mVisibleComments.get(i).isExpanded()) { + int placeholderPosition = i + mVisibleComments.get(i).getChildren().size(); + + if(!mVisibleComments.get(i).getFullName() + .equals(mVisibleComments.get(placeholderPosition).getFullName())) { + for(int j = i + 1; j < mVisibleComments.size(); j++) { + if(mVisibleComments.get(j).getFullName().equals(mVisibleComments.get(i).getFullName())) { + placeholderPosition = j; + } + } + } + + mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); + mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(false); + placeholderTextView.setText(R.string.comment_load_more_comments); + + mVisibleComments.addAll(placeholderPosition, expandedComments); + notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); + } + + mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1) + .setLoadingMoreChildren(false); + mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1) + .setLoadMoreChildrenFailed(false); + mVisibleComments.get(i).addChildren(expandedComments); + + break; + } + } + } + } + + @Override + public void onFetchMoreCommentFailed() { + if(parentPosition < mVisibleComments.size() + && parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) { + if(mVisibleComments.get(parentPosition).isExpanded()) { + int placeholderPosition = getAdapterPosition() - 1; + if(!mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { + for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { + placeholderPosition = i; + break; + } + } + } + + mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); + mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(true); + placeholderTextView.setText(R.string.comment_load_more_comments_failed); + } + + mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) + .setLoadingMoreChildren(false); + mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) + .setLoadMoreChildrenFailed(true); + } else { + for(int i = 0; i < mVisibleComments.size(); i++) { + if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { + if(mVisibleComments.get(i).isExpanded()) { + int placeholderPosition = i + mVisibleComments.get(i).getChildren().size(); + if(!mVisibleComments.get(placeholderPosition).getFullName().equals(mVisibleComments.get(i).getFullName())) { + for(int j = i + 1; j < mVisibleComments.size(); j++) { + if(mVisibleComments.get(j).getFullName().equals(mVisibleComments.get(i).getFullName())) { + placeholderPosition = j; + break; + } + } + } + + mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); + mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(true); + placeholderTextView.setText(R.string.comment_load_more_comments_failed); + } + + mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1).setLoadingMoreChildren(false); + mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1).setLoadMoreChildrenFailed(true); + + break; + } + } + } + } + }); + }); + } + } + + class LoadCommentsViewHolder extends RecyclerView.ViewHolder { + LoadCommentsViewHolder(@NonNull View itemView) { + super(itemView); + } + } + + class LoadCommentsFailedViewHolder extends RecyclerView.ViewHolder { + LoadCommentsFailedViewHolder(@NonNull View itemView) { + super(itemView); + } + } + + class NoCommentViewHolder extends RecyclerView.ViewHolder { + NoCommentViewHolder(@NonNull View itemView) { + super(itemView); + } + } + + class IsLoadingMoreCommentsViewHolder extends RecyclerView.ViewHolder { + IsLoadingMoreCommentsViewHolder(@NonNull View itemView) { + super(itemView); + } + } + + class LoadMoreCommentsFailedViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.error_text_view_item_comment_footer_error) TextView errorTextView; + @BindView(R.id.retry_button_item_comment_footer_error) Button retryButton; + + LoadMoreCommentsFailedViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + retryButton.setOnClickListener(view -> mCommentRecyclerViewAdapterCallback.retryFetchingMoreComments()); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java deleted file mode 100644 index 32b023be..00000000 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentRecyclerViewAdapter.java +++ /dev/null @@ -1,1185 +0,0 @@ -package ml.docilealligator.infinityforreddit; - -import android.app.Activity; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.ColorFilter; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -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 androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.browser.customtabs.CustomTabsIntent; -import androidx.core.content.ContextCompat; -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.libRG.CustomTextView; -import com.santalu.aspectratioimageview.AspectRatioImageView; - -import java.util.ArrayList; -import java.util.Locale; - -import CustomView.AspectRatioGifImageView; -import SubredditDatabase.SubredditRoomDatabase; -import User.UserRoomDatabase; -import butterknife.BindView; -import butterknife.ButterKnife; -import jp.wasabeef.glide.transformations.BlurTransformation; -import jp.wasabeef.glide.transformations.RoundedCornersTransformation; -import retrofit2.Retrofit; -import ru.noties.markwon.SpannableConfiguration; -import ru.noties.markwon.view.MarkwonView; - -class CommentRecyclerViewAdapter extends RecyclerView.Adapter { - private static final int VIEW_TYPE_POST_DETAIL = 0; - 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_CHILD_COMMENTS = 5; - private static final int VIEW_TYPE_IS_LOADING_MORE_COMMENTS = 6; - private static final int VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED = 7; - - private Activity mActivity; - private Retrofit mRetrofit; - private Retrofit mOauthRetrofit; - private RequestManager mGlide; - private SharedPreferences mSharedPreferences; - private Post mPost; - private ArrayList mVisibleComments; - private String mSubredditNamePrefixed; - private Locale mLocale; - private CommentRecyclerViewAdapterCallback mCommentRecyclerViewAdapterCallback; - private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; - private boolean isInitiallyLoading; - private boolean isInitiallyLoadingFailed; - private boolean mHasMoreComments; - private boolean loadMoreCommentsFailed; - - interface CommentRecyclerViewAdapterCallback { - void updatePost(Post post); - void retryFetchingMoreComments(); - } - - CommentRecyclerViewAdapter(Activity activity, Retrofit retrofit, Retrofit oauthRetrofit, RequestManager glide, - SharedPreferences sharedPreferences, Post post, String subredditNamePrefixed, - Locale locale, LoadSubredditIconAsyncTask loadSubredditIconAsyncTask, - CommentRecyclerViewAdapterCallback commentRecyclerViewAdapterCallback) { - mActivity = activity; - mRetrofit = retrofit; - mOauthRetrofit = oauthRetrofit; - mGlide = glide; - mSharedPreferences = sharedPreferences; - mPost = post; - mVisibleComments = new ArrayList<>(); - mSubredditNamePrefixed = subredditNamePrefixed; - mLocale = locale; - mLoadSubredditIconAsyncTask = loadSubredditIconAsyncTask; - mCommentRecyclerViewAdapterCallback = commentRecyclerViewAdapterCallback; - isInitiallyLoading = true; - isInitiallyLoadingFailed = false; - mHasMoreComments = false; - loadMoreCommentsFailed = false; - } - - @Override - public int getItemViewType(int 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; - } - } - } - - if(position == mVisibleComments.size() + 1) { - if(mHasMoreComments) { - return VIEW_TYPE_IS_LOADING_MORE_COMMENTS; - } else { - return VIEW_TYPE_LOAD_MORE_COMMENTS_FAILED; - } - } - - CommentData comment = mVisibleComments.get(position - 1); - if(!comment.isPlaceHolder()) { - return VIEW_TYPE_COMMENT; - } else { - return VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS; - } - } - - @NonNull - @Override - public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - switch (viewType) { - case VIEW_TYPE_POST_DETAIL: - return new PostDetailViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_detail, parent, false)); - case VIEW_TYPE_FIRST_LOADING: - return new LoadCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments, parent, false)); - case VIEW_TYPE_FIRST_LOADING_FAILED: - return new LoadCommentsFailedViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_comments_failed_placeholder, parent, false)); - case VIEW_TYPE_NO_COMMENT_PLACEHOLDER: - return new NoCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_no_comment_placeholder, parent, false)); - case VIEW_TYPE_COMMENT: - return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment, parent, false)); - case VIEW_TYPE_LOAD_MORE_CHILD_COMMENTS: - return new LoadMoreChildCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_load_more_comments_placeholder, parent, false)); - case VIEW_TYPE_IS_LOADING_MORE_COMMENTS: - return new IsLoadingMoreCommentsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment_footer_loading, parent, false)); - default: - return new LoadMoreCommentsFailedViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_comment_footer_error, parent, false)); - } - } - - @Override - public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { - if(holder.getItemViewType() == VIEW_TYPE_POST_DETAIL) { - ((PostDetailViewHolder) holder).mTitleTextView.setText(mPost.getTitle()); - - if(mPost.getSubredditNamePrefixed().equals("u/" + mPost.getAuthor())) { - if(mPost.getAuthorIconUrl() == null) { - new LoadUserDataAsyncTask(UserRoomDatabase.getDatabase(mActivity).userDao(), mPost.getAuthor(), mOauthRetrofit, iconImageUrl -> { - if(mActivity != null && getItemCount() > 0) { - 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); - } - - if(holder.getAdapterPosition() >= 0) { - mPost.setAuthorIconUrl(iconImageUrl); - } - } - }).execute(); - } else if(!mPost.getAuthorIconUrl().equals("")) { - mGlide.load(mPost.getAuthorIconUrl()) - .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); - } - } else { - if(mPost.getSubredditIconUrl() == null) { - if(mLoadSubredditIconAsyncTask != null) { - mLoadSubredditIconAsyncTask.cancel(true); - } - 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.isSpoiler() || mPost.getFlair() != null) { - ((PostDetailViewHolder) holder).spoilerFlairlinearLayout.setVisibility(View.VISIBLE); - } - - if(mPost.isSpoiler()) { - ((PostDetailViewHolder) holder).spoilerTextView.setVisibility(View.VISIBLE); - ((PostDetailViewHolder) holder).spoilerTextView - .setBackgroundColor(mActivity.getResources().getColor(R.color.backgroundColorPrimaryDark)); - } - - if(mPost.getFlair() != null) { - ((PostDetailViewHolder) holder).flairTextView.setVisibility(View.VISIBLE); - ((PostDetailViewHolder) holder).flairTextView.setText(mPost.getFlair()); - ((PostDetailViewHolder) holder).flairTextView - .setBackgroundColor(mActivity.getResources().getColor(R.color.backgroundColorPrimaryDark)); - } - - 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 comment = mVisibleComments.get(holder.getAdapterPosition() - 1); - - String authorPrefixed = "u/" + comment.getAuthor(); - ((CommentViewHolder) holder).authorTextView.setText(authorPrefixed); - - ((CommentViewHolder) holder).commentTimeTextView.setText(comment.getCommentTime()); - - SpannableConfiguration spannableConfiguration = SpannableConfiguration.builder(mActivity).linkResolver((view, link) -> { - if (link.startsWith("/u/") || link.startsWith("u/")) { - Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3)); - mActivity.startActivity(intent); - } else if (link.startsWith("/r/") || link.startsWith("r/")) { - Intent intent = new Intent(mActivity, ViewSubredditDetailActivity.class); - intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3)); - mActivity.startActivity(intent); - } else { - CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); - // add share action to menu list - builder.addDefaultShareMenuItem(); - builder.setToolbarColor(mActivity.getResources().getColor(R.color.colorPrimary)); - CustomTabsIntent customTabsIntent = builder.build(); - customTabsIntent.launchUrl(mActivity, Uri.parse(link)); - } - }).build(); - - ((CommentViewHolder) holder).commentMarkdownView.setMarkdown(spannableConfiguration, comment.getCommentContent()); - ((CommentViewHolder) holder).scoreTextView.setText(Integer.toString(comment.getScore())); - - ViewGroup.LayoutParams params = ((CommentViewHolder) holder).verticalBlock.getLayoutParams(); - params.width = comment.getDepth() * 16; - ((CommentViewHolder) holder).verticalBlock.setLayoutParams(params); - - if (comment.hasReply()) { - if(comment.isExpanded()) { - ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); - } else { - ((CommentViewHolder) holder).expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); - } - ((CommentViewHolder) holder).expandButton.setVisibility(View.VISIBLE); - } - - switch (comment.getVoteType()) { - case 1: - ((CommentViewHolder) holder).upvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); - break; - case 2: - ((CommentViewHolder) holder).downvoteButton - .setColorFilter(ContextCompat.getColor(mActivity, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); - break; - } - } else if(holder instanceof LoadMoreChildCommentsViewHolder) { - CommentData placeholder; - placeholder = mVisibleComments.get(holder.getAdapterPosition() - 1); - - ViewGroup.LayoutParams params = ((LoadMoreChildCommentsViewHolder) holder).verticalBlock.getLayoutParams(); - params.width = placeholder.getDepth() * 16; - ((LoadMoreChildCommentsViewHolder) holder).verticalBlock.setLayoutParams(params); - - if(placeholder.isLoadingMoreChildren()) { - ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.loading); - } else if(placeholder.isLoadMoreChildrenFailed()) { - ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments_failed); - } else { - ((LoadMoreChildCommentsViewHolder) holder).placeholderTextView.setText(R.string.comment_load_more_comments); - } - } else if(holder instanceof LoadMoreCommentsFailedViewHolder) { - ((LoadMoreCommentsFailedViewHolder) holder).errorTextView.setText(R.string.post_load_comments_failed); - } - } - - private void loadImage(PostDetailViewHolder holder) { - RequestBuilder imageRequestBuilder = mGlide.load(mPost.getPreviewUrl()) - .apply(new RequestOptions().override(mPost.getPreviewWidth(), mPost.getPreviewHeight())) - .listener(new RequestListener() { - @Override - public boolean onLoadFailed(@Nullable GlideException e, Object model, Target 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 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) { - int childDepth = mVisibleComments.get(position).getDepth(); - for(int i = position; i >= 0; i--) { - if(mVisibleComments.get(i).getDepth() < childDepth) { - return i; - } - } - return -1; - } - - private void expandChildren(int position) { - CommentData comment = mVisibleComments.get(position); - if(!comment.isExpanded()) { - comment.setExpanded(true); - ArrayList children = comment.getChildren(); - if(children != null && children.size() > 0) { - for(int i = 0; i < children.size(); i++) { - children.get(i).setExpanded(false); - } - mVisibleComments.addAll(position + 1, children); - notifyItemRangeInserted(position + 2, children.size()); - } - } - } - - private void collapseChildren(int position) { - mVisibleComments.get(position).setExpanded(false); - int depth = mVisibleComments.get(position).getDepth(); - int allChildrenSize = 0; - for(int i = position + 1; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getDepth() > depth) { - allChildrenSize++; - } else { - break; - } - } - - mVisibleComments.subList(position + 1, position + 1 + allChildrenSize).clear(); - notifyItemRangeRemoved(position + 2, allChildrenSize); - } - - void addComments(ArrayList comments, boolean hasMoreComments) { - if(mVisibleComments.size() == 0) { - isInitiallyLoading = false; - isInitiallyLoadingFailed = false; - if(comments.size() == 0) { - notifyItemChanged(1); - } else { - notifyItemRemoved(1); - } - } - - int sizeBefore = mVisibleComments.size(); - mVisibleComments.addAll(comments); - notifyItemRangeInserted(sizeBefore + 1, comments.size()); - - if(mHasMoreComments != hasMoreComments) { - if(hasMoreComments) { - notifyItemInserted(mVisibleComments.size() + 1); - } else { - notifyItemRemoved(mVisibleComments.size() + 1); - } - } - mHasMoreComments = hasMoreComments; - } - - void addComment(CommentData comment) { - if(mVisibleComments.size() == 0 || isInitiallyLoadingFailed) { - notifyItemRemoved(1); - } - - mVisibleComments.add(0, comment); - - if(isInitiallyLoading) { - notifyItemInserted(2); - } else { - notifyItemInserted(1); - } - } - - void addChildComment(CommentData comment, String parentFullname, int parentPosition) { - if(!parentFullname.equals(mVisibleComments.get(parentPosition).getFullName())) { - for(int i = 0; i < mVisibleComments.size(); i++) { - if(parentFullname.equals(mVisibleComments.get(i).getFullName())) { - parentPosition = i; - break; - } - } - } - - mVisibleComments.get(parentPosition).addChild(comment); - mVisibleComments.get(parentPosition).setHasReply(true); - if(!mVisibleComments.get(parentPosition).isExpanded()) { - expandChildren(parentPosition); - notifyItemChanged(parentPosition + 1); - } else { - mVisibleComments.add(parentPosition + 1, comment); - notifyItemInserted(parentPosition + 2); - } - } - - void initiallyLoading() { - if(mLoadSubredditIconAsyncTask != null) { - mLoadSubredditIconAsyncTask.cancel(true); - } - - if(mVisibleComments.size() != 0) { - int previousSize = mVisibleComments.size(); - mVisibleComments.clear(); - notifyItemRangeRemoved(1, previousSize); - } - - if(isInitiallyLoading || isInitiallyLoadingFailed || mVisibleComments.size() == 0) { - isInitiallyLoading = true; - isInitiallyLoadingFailed = false; - notifyItemChanged(1); - } else { - isInitiallyLoading = true; - isInitiallyLoadingFailed = false; - notifyItemInserted(1); - } - } - - void initiallyLoadCommentsFailed() { - isInitiallyLoading = false; - isInitiallyLoadingFailed = true; - notifyItemChanged(1); - } - - void loadMoreCommentsFailed() { - loadMoreCommentsFailed = true; - notifyItemChanged(mVisibleComments.size() + 1); - } - - ArrayList getVisibleComments() { - return mVisibleComments; - } - - @Override - public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { - if (holder instanceof CommentViewHolder) { - ((CommentViewHolder) holder).expandButton.setVisibility(View.GONE); - ((CommentViewHolder) holder).upvoteButton.clearColorFilter(); - ((CommentViewHolder) holder).downvoteButton.clearColorFilter(); - } - } - - @Override - public int getItemCount() { - if(isInitiallyLoading || isInitiallyLoadingFailed || mVisibleComments.size() == 0) { - return 2; - } - - if(mHasMoreComments || loadMoreCommentsFailed) { - return mVisibleComments.size() + 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_gif_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.spoiler_flair_linear_layout_item_post_detail) LinearLayout spoilerFlairlinearLayout; - @BindView(R.id.spoiler_custom_text_view_item_post_detail) CustomTextView spoilerTextView; - @BindView(R.id.flair_custom_text_view_item_post_detail) CustomTextView flairTextView; - @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; - - PostDetailViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - - mSubredditIconNameLinearLayout.setOnClickListener(view -> { - Intent intent; - if(mPost.getSubredditNamePrefixed().equals("u/" + mPost.getAuthor())) { - intent = new Intent(mActivity, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mPost.getAuthor()); - } else { - 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())); - - mCommentRecyclerViewAdapterCallback.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())); - - mCommentRecyclerViewAdapterCallback.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); - - mCommentRecyclerViewAdapterCallback.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())); - - mCommentRecyclerViewAdapterCallback.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())); - - mCommentRecyclerViewAdapterCallback.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); - - mCommentRecyclerViewAdapterCallback.updatePost(mPost); - } - }, mPost.getFullName(), newVoteType); - }); - } - } - - class CommentViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.author_text_view_item_post_comment) TextView authorTextView; - @BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView; - @BindView(R.id.comment_markdown_view_item_post_comment) MarkwonView commentMarkdownView; - @BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton; - @BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView; - @BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton; - @BindView(R.id.expand_button_item_post_comment) ImageView expandButton; - @BindView(R.id.share_button_item_post_comment) ImageView shareButton; - @BindView(R.id.reply_button_item_post_comment) ImageView replyButton; - @BindView(R.id.vertical_block_item_post_comment) View verticalBlock; - - CommentViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - - authorTextView.setOnClickListener(view -> { - Intent intent = new Intent(mActivity, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getAuthor()); - mActivity.startActivity(intent); - }); - - shareButton.setOnClickListener(view -> { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - String extraText = mVisibleComments.get(getAdapterPosition() - 1).getPermalink(); - intent.putExtra(Intent.EXTRA_TEXT, extraText); - mActivity.startActivity(Intent.createChooser(intent, "Share")); - }); - - expandButton.setOnClickListener(view -> { - if(mVisibleComments.get(getAdapterPosition() - 1).isExpanded()) { - collapseChildren(getAdapterPosition() - 1); - expandButton.setImageResource(R.drawable.ic_expand_more_black_20dp); - } else { - expandChildren(getAdapterPosition() - 1); - mVisibleComments.get(getAdapterPosition() - 1).setExpanded(true); - expandButton.setImageResource(R.drawable.ic_expand_less_black_20dp); - } - }); - - replyButton.setOnClickListener(view -> { - Intent intent = new Intent(mActivity, CommentActivity.class); - intent.putExtra(CommentActivity.EXTRA_PARENT_DEPTH_KEY, mVisibleComments.get(getAdapterPosition() - 1).getDepth() + 1); - intent.putExtra(CommentActivity.EXTRA_COMMENT_PARENT_TEXT_KEY, mVisibleComments.get(getAdapterPosition() - 1).getCommentContent()); - intent.putExtra(CommentActivity.EXTRA_PARENT_FULLNAME_KEY, mVisibleComments.get(getAdapterPosition() - 1).getFullName()); - intent.putExtra(CommentActivity.EXTRA_IS_REPLYING_KEY, true); - intent.putExtra(CommentActivity.EXTRA_PARENT_POSITION_KEY, getAdapterPosition() - 1); - mActivity.startActivityForResult(intent, CommentActivity.WRITE_COMMENT_REQUEST_CODE); - }); - - upvoteButton.setOnClickListener(view -> { - int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType(); - String newVoteType; - - downvoteButton.clearColorFilter(); - - if(previousVoteType != CommentData.VOTE_TYPE_UPVOTE) { - //Not upvoted before - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE); - newVoteType = RedditUtils.DIR_UPVOTE; - upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - //Upvoted before - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); - newVoteType = RedditUtils.DIR_UNVOTE; - upvoteButton.clearColorFilter(); - } - - scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); - - VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position) { - if(newVoteType.equals(RedditUtils.DIR_UPVOTE)) { - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_UPVOTE); - upvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.backgroundColorPrimaryDark), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); - upvoteButton.clearColorFilter(); - } - - downvoteButton.clearColorFilter(); - scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); - } - - @Override - public void onVoteThingFail(int position) { } - }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition()); - }); - - downvoteButton.setOnClickListener(view -> { - int previousVoteType = mVisibleComments.get(getAdapterPosition() - 1).getVoteType(); - String newVoteType; - - upvoteButton.clearColorFilter(); - - if(previousVoteType != CommentData.VOTE_TYPE_DOWNVOTE) { - //Not downvoted before - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); - newVoteType = RedditUtils.DIR_DOWNVOTE; - downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - //Downvoted before - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); - newVoteType = RedditUtils.DIR_UNVOTE; - downvoteButton.clearColorFilter(); - } - - scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); - - VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() { - @Override - public void onVoteThingSuccess(int position1) { - if(newVoteType.equals(RedditUtils.DIR_DOWNVOTE)) { - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_DOWNVOTE); - downvoteButton.setColorFilter(ContextCompat.getColor(mActivity, R.color.colorAccent), android.graphics.PorterDuff.Mode.SRC_IN); - } else { - mVisibleComments.get(getAdapterPosition() - 1).setVoteType(CommentData.VOTE_TYPE_NO_VOTE); - downvoteButton.clearColorFilter(); - } - - upvoteButton.clearColorFilter(); - scoreTextView.setText(Integer.toString(mVisibleComments.get(getAdapterPosition() - 1).getScore() + mVisibleComments.get(getAdapterPosition() - 1).getVoteType())); - } - - @Override - public void onVoteThingFail(int position1) { } - }, mVisibleComments.get(getAdapterPosition() - 1).getFullName(), newVoteType, getAdapterPosition()); - }); - } - } - - class LoadMoreChildCommentsViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.vertical_block_item_load_more_comments) View verticalBlock; - @BindView(R.id.placeholder_text_view_item_load_more_comments) TextView placeholderTextView; - - LoadMoreChildCommentsViewHolder(View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - - placeholderTextView.setOnClickListener(view -> { - int parentPosition = getParentPosition(getAdapterPosition() - 1); - CommentData parentComment = mVisibleComments.get(parentPosition); - - mVisibleComments.get(getAdapterPosition() - 1).setLoadingMoreChildren(true); - mVisibleComments.get(getAdapterPosition() - 1).setLoadMoreChildrenFailed(false); - placeholderTextView.setText(R.string.loading); - - FetchComment.fetchMoreComment(mRetrofit, mSubredditNamePrefixed, parentComment.getMoreChildrenFullnames(), - parentComment.getMoreChildrenStartingIndex(), parentComment.getDepth() + 1, mLocale, - new FetchComment.FetchMoreCommentListener() { - @Override - public void onFetchMoreCommentSuccess(ArrayList expandedComments, - int childrenStartingIndex) { - if(mVisibleComments.size() > parentPosition - && parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) { - if(mVisibleComments.get(parentPosition).isExpanded()) { - if(mVisibleComments.get(parentPosition).getChildren().size() > childrenStartingIndex) { - mVisibleComments.get(parentPosition).setMoreChildrenStartingIndex(childrenStartingIndex); - mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) - .setLoadingMoreChildren(false); - mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) - .setLoadMoreChildrenFailed(false); - - int placeholderPosition = getAdapterPosition() - 1; - if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { - for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { - placeholderPosition = i; - break; - } - } - } - - mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); - mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(false); - placeholderTextView.setText(R.string.comment_load_more_comments); - - mVisibleComments.addAll(placeholderPosition, expandedComments); - notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); - } else { - mVisibleComments.get(parentPosition).getChildren() - .remove(mVisibleComments.get(parentPosition).getChildren().size() - 1); - mVisibleComments.get(parentPosition).removeMoreChildrenFullnames(); - - int placeholderPosition = getAdapterPosition() - 1; - if(mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { - for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { - placeholderPosition = i; - break; - } - } - } - - mVisibleComments.remove(placeholderPosition); - notifyItemRemoved(placeholderPosition + 1); - - mVisibleComments.addAll(placeholderPosition, expandedComments); - notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); - } - } else { - if(mVisibleComments.get(parentPosition).hasReply() && mVisibleComments.get(parentPosition).getChildren().size() <= childrenStartingIndex) { - mVisibleComments.get(parentPosition).getChildren() - .remove(mVisibleComments.get(parentPosition).getChildren().size() - 1); - mVisibleComments.get(parentPosition).removeMoreChildrenFullnames(); - } - } - - mVisibleComments.get(parentPosition).addChildren(expandedComments); - } else { - for(int i = 0; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { - if(mVisibleComments.get(i).isExpanded()) { - int placeholderPosition = i + mVisibleComments.get(i).getChildren().size(); - - if(!mVisibleComments.get(i).getFullName() - .equals(mVisibleComments.get(placeholderPosition).getFullName())) { - for(int j = i + 1; j < mVisibleComments.size(); j++) { - if(mVisibleComments.get(j).getFullName().equals(mVisibleComments.get(i).getFullName())) { - placeholderPosition = j; - } - } - } - - mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); - mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(false); - placeholderTextView.setText(R.string.comment_load_more_comments); - - mVisibleComments.addAll(placeholderPosition, expandedComments); - notifyItemRangeInserted(placeholderPosition + 1, expandedComments.size()); - } - - mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1) - .setLoadingMoreChildren(false); - mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1) - .setLoadMoreChildrenFailed(false); - mVisibleComments.get(i).addChildren(expandedComments); - - break; - } - } - } - } - - @Override - public void onFetchMoreCommentFailed() { - if(parentPosition < mVisibleComments.size() - && parentComment.getFullName().equals(mVisibleComments.get(parentPosition).getFullName())) { - if(mVisibleComments.get(parentPosition).isExpanded()) { - int placeholderPosition = getAdapterPosition() - 1; - if(!mVisibleComments.get(getAdapterPosition() - 1).getFullName().equals(parentComment.getFullName())) { - for(int i = parentPosition + 1; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { - placeholderPosition = i; - break; - } - } - } - - mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); - mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(true); - placeholderTextView.setText(R.string.comment_load_more_comments_failed); - } - - mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) - .setLoadingMoreChildren(false); - mVisibleComments.get(parentPosition).getChildren().get(mVisibleComments.get(parentPosition).getChildren().size() - 1) - .setLoadMoreChildrenFailed(true); - } else { - for(int i = 0; i < mVisibleComments.size(); i++) { - if(mVisibleComments.get(i).getFullName().equals(parentComment.getFullName())) { - if(mVisibleComments.get(i).isExpanded()) { - int placeholderPosition = i + mVisibleComments.get(i).getChildren().size(); - if(!mVisibleComments.get(placeholderPosition).getFullName().equals(mVisibleComments.get(i).getFullName())) { - for(int j = i + 1; j < mVisibleComments.size(); j++) { - if(mVisibleComments.get(j).getFullName().equals(mVisibleComments.get(i).getFullName())) { - placeholderPosition = j; - break; - } - } - } - - mVisibleComments.get(placeholderPosition).setLoadingMoreChildren(false); - mVisibleComments.get(placeholderPosition).setLoadMoreChildrenFailed(true); - placeholderTextView.setText(R.string.comment_load_more_comments_failed); - } - - mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1).setLoadingMoreChildren(false); - mVisibleComments.get(i).getChildren().get(mVisibleComments.get(i).getChildren().size() - 1).setLoadMoreChildrenFailed(true); - - break; - } - } - } - } - }); - }); - } - } - - class LoadCommentsViewHolder extends RecyclerView.ViewHolder { - LoadCommentsViewHolder(@NonNull View itemView) { - super(itemView); - } - } - - class LoadCommentsFailedViewHolder extends RecyclerView.ViewHolder { - LoadCommentsFailedViewHolder(@NonNull View itemView) { - super(itemView); - } - } - - class NoCommentViewHolder extends RecyclerView.ViewHolder { - NoCommentViewHolder(@NonNull View itemView) { - super(itemView); - } - } - - class IsLoadingMoreCommentsViewHolder extends RecyclerView.ViewHolder { - IsLoadingMoreCommentsViewHolder(@NonNull View itemView) { - super(itemView); - } - } - - class LoadMoreCommentsFailedViewHolder extends RecyclerView.ViewHolder { - @BindView(R.id.error_text_view_item_comment_footer_error) TextView errorTextView; - @BindView(R.id.retry_button_item_comment_footer_error) Button retryButton; - - LoadMoreCommentsFailedViewHolder(@NonNull View itemView) { - super(itemView); - ButterKnife.bind(this, itemView); - - retryButton.setOnClickListener(view -> mCommentRecyclerViewAdapterCallback.retryFetchingMoreComments()); - } - } -} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java index 3feda5cf..7f92697a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java @@ -76,4 +76,7 @@ public class JSONUtils { static final String VALUE_KEY = "value"; static final String TEXT_KEY = "text"; static final String SPOILER_KEY = "spoiler"; + static final String RULES_KEY = "rules"; + static final String SHORT_NAME_KEY = "short_name"; + static final String DESCRIPTION_HTML_KEY = "description_html"; } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostImageActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostImageActivity.java index 1ba869c3..0d8a258c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostImageActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostImageActivity.java @@ -179,6 +179,20 @@ public class PostImageActivity extends AppCompatActivity implements FlairBottomS startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); }); + rulesButton.setOnClickListener(view -> { + if(subredditName == null) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + } else { + Intent intent = new Intent(this, RulesActivity.class); + if(subredditIsUser) { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, subredditName); + } + startActivity(intent); + } + }); + flairTextView.setOnClickListener(view -> { if(flair == null) { flairSelectionBottomSheetFragment = new FlairBottomSheetFragment(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostLinkActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostLinkActivity.java index 7260c5af..c0067e88 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostLinkActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostLinkActivity.java @@ -150,6 +150,20 @@ public class PostLinkActivity extends AppCompatActivity implements FlairBottomSh startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); }); + rulesButton.setOnClickListener(view -> { + if(subredditName == null) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + } else { + Intent intent = new Intent(this, RulesActivity.class); + if(subredditIsUser) { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, subredditName); + } + startActivity(intent); + } + }); + flairTextView.setOnClickListener(view -> { if(flair == null) { flairSelectionBottomSheetFragment = new FlairBottomSheetFragment(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostTextActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostTextActivity.java index c943e88e..828f556c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostTextActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostTextActivity.java @@ -151,6 +151,20 @@ public class PostTextActivity extends AppCompatActivity implements FlairBottomSh startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); }); + rulesButton.setOnClickListener(view -> { + if(subredditName == null) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + } else { + Intent intent = new Intent(this, RulesActivity.class); + if(subredditIsUser) { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, subredditName); + } + startActivity(intent); + } + }); + flairTextView.setOnClickListener(view -> { if(flair == null) { flairSelectionBottomSheetFragment = new FlairBottomSheetFragment(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostVideoActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostVideoActivity.java index 7432a0b7..23214037 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostVideoActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostVideoActivity.java @@ -184,6 +184,20 @@ public class PostVideoActivity extends AppCompatActivity implements FlairBottomS startActivityForResult(intent, SUBREDDIT_SELECTION_REQUEST_CODE); }); + rulesButton.setOnClickListener(view -> { + if(subredditName == null) { + Snackbar.make(coordinatorLayout, R.string.select_a_subreddit, Snackbar.LENGTH_SHORT).show(); + } else { + Intent intent = new Intent(this, RulesActivity.class); + if(subredditIsUser) { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, "u_" + subredditName); + } else { + intent.putExtra(RulesActivity.EXTRA_SUBREDDIT_NAME, subredditName); + } + startActivity(intent); + } + }); + flairTextView.setOnClickListener(view -> { if(flair == null) { flairSelectionBottomSheetFragment = new FlairBottomSheetFragment(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java index b4dc3d97..75e99f7e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java @@ -95,6 +95,9 @@ public interface RedditAPI { @GET("r/{subredditName}/api/link_flair.json?raw_json=1") Call getFlairs(@HeaderMap Map headers, @Path("subredditName") String subredditName); + @GET("/r/{subredditName}/about/rules.json?raw_json=1") + Call getRules(@Path("subredditName") String subredditName); + @Multipart @POST(".") Call uploadMediaToAWS(@PartMap()Map params, @Part() MultipartBody.Part file); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/Rule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/Rule.java new file mode 100644 index 00000000..89b4d26d --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/Rule.java @@ -0,0 +1,19 @@ +package ml.docilealligator.infinityforreddit; + +class Rule { + private String shortName; + private String descriptionHtml; + + Rule(String shortName, String descriptionHtml) { + this.shortName = shortName; + this.descriptionHtml = descriptionHtml; + } + + String getShortName() { + return shortName; + } + + String getDescriptionHtml() { + return descriptionHtml; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RulesActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RulesActivity.java new file mode 100644 index 00000000..18584546 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RulesActivity.java @@ -0,0 +1,170 @@ +package ml.docilealligator.infinityforreddit; + +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + +import javax.inject.Inject; +import javax.inject.Named; + +import butterknife.BindView; +import butterknife.ButterKnife; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; + +public class RulesActivity extends AppCompatActivity { + + static final String EXTRA_SUBREDDIT_NAME = "ESN"; + + @BindView(R.id.progress_bar_rules_activity) ProgressBar progressBar; + @BindView(R.id.recycler_view_rules_activity) RecyclerView recyclerView; + @BindView(R.id.error_text_view_rules_activity) TextView errorTextView; + + private String mSubredditName; + + private RulesRecyclerViewAdapter mAdapter; + + @Inject + @Named("no_oauth") + Retrofit mRetrofit; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_rules); + + ButterKnife.bind(this); + + ((Infinity) getApplication()).getmAppComponent().inject(this); + + ActionBar actionBar = getSupportActionBar(); + Drawable upArrow = getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp); + actionBar.setHomeAsUpIndicator(upArrow); + + mSubredditName = getIntent().getExtras().getString(EXTRA_SUBREDDIT_NAME); + + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + mAdapter = new RulesRecyclerViewAdapter(this); + recyclerView.setAdapter(mAdapter); + + fetchRules(); + } + + private void fetchRules() { + progressBar.setVisibility(View.VISIBLE); + errorTextView.setVisibility(View.GONE); + + RedditAPI api = mRetrofit.create(RedditAPI.class); + Call rulesCall = api.getRules(mSubredditName); + rulesCall.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if(response.isSuccessful()) { + new ParseRulesAsyncTask(response.body(), new ParseRulesAsyncTask.ParseRulesAsyncTaskListener() { + @Override + public void parseSuccessful(ArrayList rules) { + progressBar.setVisibility(View.GONE); + if(rules == null || rules.size() == 0) { + errorTextView.setVisibility(View.VISIBLE); + errorTextView.setText(R.string.no_rule); + errorTextView.setOnClickListener(view -> {}); + } + mAdapter.changeDataset(rules); + } + + @Override + public void parseFailed() { + displayError(); + } + }).execute(); + } else { + displayError(); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + displayError(); + } + }); + } + + private void displayError() { + progressBar.setVisibility(View.GONE); + errorTextView.setVisibility(View.VISIBLE); + errorTextView.setText(R.string.error_loading_rules); + errorTextView.setOnClickListener(view -> fetchRules()); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if(item.getItemId() == android.R.id.home) { + finish(); + return true; + } + + return false; + } + + private static class ParseRulesAsyncTask extends AsyncTask, ArrayList> { + private String response; + private ParseRulesAsyncTaskListener parseRulesAsyncTaskListener; + + interface ParseRulesAsyncTaskListener { + void parseSuccessful(ArrayList rules); + void parseFailed(); + } + + ParseRulesAsyncTask(String response, ParseRulesAsyncTaskListener parseRulesAsyncTaskListener) { + this.response = response; + this.parseRulesAsyncTaskListener = parseRulesAsyncTaskListener; + } + + @Override + protected ArrayList doInBackground(Void... voids) { + try { + JSONArray rulesArray = new JSONObject(response).getJSONArray(JSONUtils.RULES_KEY); + ArrayList rules = new ArrayList<>(); + for(int i = 0; i < rulesArray.length(); i++) { + String shortName = rulesArray.getJSONObject(i).getString(JSONUtils.SHORT_NAME_KEY); + String descriptionHtml = null; + if(rulesArray.getJSONObject(i).has(JSONUtils.DESCRIPTION_HTML_KEY)) { + descriptionHtml = rulesArray.getJSONObject(i).getString(JSONUtils.DESCRIPTION_HTML_KEY); + } + rules.add(new Rule(shortName, descriptionHtml)); + } + return rules; + } catch (JSONException e) { + e.printStackTrace(); + } + return null; + } + + @Override + protected void onPostExecute(ArrayList rules) { + if(rules != null) { + parseRulesAsyncTaskListener.parseSuccessful(rules); + } else { + parseRulesAsyncTaskListener.parseFailed(); + } + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RulesRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RulesRecyclerViewAdapter.java new file mode 100644 index 00000000..941b0316 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RulesRecyclerViewAdapter.java @@ -0,0 +1,67 @@ +package ml.docilealligator.infinityforreddit; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; + +import CustomView.CustomMarkwonView; +import butterknife.BindView; +import butterknife.ButterKnife; + +class RulesRecyclerViewAdapter extends RecyclerView.Adapter { + private Context context; + private ArrayList rules; + + RulesRecyclerViewAdapter(Context context) { + this.context = context; + } + + @NonNull + @Override + public RuleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new RuleViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rule, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RuleViewHolder holder, int position) { + holder.shortNameTextView.setText(rules.get(holder.getAdapterPosition()).getShortName()); + if(rules.get(holder.getAdapterPosition()).getDescriptionHtml() == null) { + holder.descriptionMarkwonView.setVisibility(View.GONE); + } else { + holder.descriptionMarkwonView.setMarkdown(rules.get(holder.getAdapterPosition()).getDescriptionHtml(), context); + } + } + + @Override + public int getItemCount() { + return rules == null ? 0 : rules.size(); + } + + @Override + public void onViewRecycled(@NonNull RuleViewHolder holder) { + super.onViewRecycled(holder); + holder.descriptionMarkwonView.setVisibility(View.VISIBLE); + } + + void changeDataset(ArrayList rules) { + this.rules = rules; + notifyDataSetChanged(); + } + + class RuleViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.short_name_text_view_item_rule) TextView shortNameTextView; + @BindView(R.id.description_markwon_view_item_rule) CustomMarkwonView descriptionMarkwonView; + + RuleViewHolder(@NonNull View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index 9b8529ed..f605666c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -65,7 +65,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { private boolean hasMoreChildren; private LinearLayoutManager mLinearLayoutManager; - private CommentRecyclerViewAdapter mAdapter; + private CommentAndPostRecyclerViewAdapter mAdapter; private LoadSubredditIconAsyncTask mLoadSubredditIconAsyncTask; @BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout; @@ -109,10 +109,10 @@ public class ViewPostDetailActivity extends AppCompatActivity { mPost = savedInstanceState.getParcelable(POST_STATE); } - mAdapter = new CommentRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, + mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit, mGlide, mSharedPreferences, mPost, mPost.getSubredditNamePrefixed(), mLocale, mLoadSubredditIconAsyncTask, - new CommentRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { + new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { @Override public void updatePost(Post post) { EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java index 3433cfb8..5bc0c163 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewSubredditDetailActivity.java @@ -45,7 +45,7 @@ import retrofit2.Retrofit; public class ViewSubredditDetailActivity extends AppCompatActivity { - static final String EXTRA_SUBREDDIT_NAME_KEY = "ESN"; + public static final String EXTRA_SUBREDDIT_NAME_KEY = "ESN"; private static final String FRAGMENT_OUT_STATE_KEY = "FOSK"; private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java index e9ab3123..64d7cdc2 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewUserDetailActivity.java @@ -42,7 +42,7 @@ import retrofit2.Retrofit; public class ViewUserDetailActivity extends AppCompatActivity { - static final String EXTRA_USER_NAME_KEY = "EUNK"; + public static final String EXTRA_USER_NAME_KEY = "EUNK"; private static final String FRAGMENT_OUT_STATE_KEY = "FOSK"; private static final String IS_IN_LAZY_MODE_STATE = "IILMS"; -- cgit v1.2.3