From fcff7784c9e7128d2226e5011dc5709772f97384 Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Mon, 22 Jul 2019 11:13:57 +0800 Subject: [PATCH] Click a comment to view the corresponding post. --- .../infinityforreddit/CommentData.java | 20 +- .../CommentsListingRecyclerViewAdapter.java | 38 +++- .../infinityforreddit/JSONUtils.java | 1 + .../infinityforreddit/ParseComment.java | 6 +- .../infinityforreddit/PostDataSource.java | 27 ++- .../infinityforreddit/RedditAPI.java | 3 + .../ViewPostDetailActivity.java | 183 +++++++++++++++--- .../res/layout/activity_view_post_detail.xml | 28 +++ .../res/layout/activity_view_user_detail.xml | 4 +- app/src/main/res/layout/item_comment.xml | 1 + app/src/main/res/values/strings.xml | 2 + 11 files changed, 259 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java index fe2806ba..e0c697b6 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentData.java @@ -15,6 +15,8 @@ class CommentData implements Parcelable { private String author; private String commentTime; private String commentContent; + private String linkId; + private String subredditName; private String parentId; private int score; private int voteType; @@ -34,13 +36,15 @@ class CommentData implements Parcelable { private boolean loadMoreChildrenFailed; CommentData(String id, String fullName, String author, String commentTime, String commentContent, - String parentId, int score, boolean isSubmitter, String permalink, int depth, - boolean collapsed, boolean hasReply, boolean scoreHidden) { + String linkId, String subredditName, String parentId, int score, boolean isSubmitter, String permalink, + int depth, boolean collapsed, boolean hasReply, boolean scoreHidden) { this.id = id; this.fullName = fullName; this.author = author; this.commentTime = commentTime; this.commentContent = commentContent; + this.linkId = linkId; + this.subredditName = subredditName; this.parentId = parentId; this.score = score; this.isSubmitter = isSubmitter; @@ -68,6 +72,8 @@ class CommentData implements Parcelable { author = in.readString(); commentTime = in.readString(); commentContent = in.readString(); + linkId = in.readString(); + subredditName = in.readString(); parentId = in.readString(); score = in.readInt(); voteType = in.readInt(); @@ -118,6 +124,14 @@ class CommentData implements Parcelable { return commentContent; } + public String getLinkId() { + return linkId; + } + + public String getSubredditName() { + return subredditName; + } + public String getParentId() { return parentId; } @@ -265,6 +279,8 @@ class CommentData implements Parcelable { parcel.writeString(author); parcel.writeString(commentTime); parcel.writeString(commentContent); + parcel.writeString(linkId); + parcel.writeString(subredditName); parcel.writeString(parentId); parcel.writeInt(score); parcel.writeInt(voteType); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java index 8075c245..6aac6a53 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/CommentsListingRecyclerViewAdapter.java @@ -18,6 +18,8 @@ import androidx.paging.PagedListAdapter; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.card.MaterialCardView; + import CustomView.CustomMarkwonView; import butterknife.BindView; import butterknife.ButterKnife; @@ -27,6 +29,8 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter DIFF_CALLBACK = new DiffUtil.ItemCallback() { @@ -80,8 +86,23 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter { + Intent intent = new Intent(mContext, ViewUserDetailActivity.class); + intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, comment.getAuthor()); + mContext.startActivity(intent); + }); + } else { + ((DataViewHolder) holder).authorTextView.setText("r/" + comment.getSubredditName()); + ((DataViewHolder) holder).authorTextView.setTextColor(colorAccent); + ((DataViewHolder) holder).authorTextView.setOnClickListener(view -> { + Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class); + intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, comment.getSubredditName()); + mContext.startActivity(intent); + }); + } ((DataViewHolder) holder).commentTimeTextView.setText(comment.getCommentTime()); @@ -144,6 +165,7 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter { - Intent intent = new Intent(mContext, ViewUserDetailActivity.class); - intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, getItem(getAdapterPosition()).getAuthor()); + cardView.setOnClickListener(view -> { + Intent intent = new Intent(mContext, ViewPostDetailActivity.class); + intent.putExtra(ViewPostDetailActivity.EXTRA_POST_ID, getItem(getAdapterPosition()).getLinkId()); mContext.startActivity(intent); }); + verticalBlock.setVisibility(View.GONE); + + commentMarkdownView.setOnClickListener(view -> cardView.callOnClick()); + RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) shareButton.getLayoutParams(); lp.addRule(RelativeLayout.ALIGN_PARENT_END); lp.setMarginEnd(0); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java index 9240ccd3..f0f72a28 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/JSONUtils.java @@ -61,6 +61,7 @@ public class JSONUtils { static final String IS_FRIEND_KEY = "is_friend"; static final String JSON_KEY = "json"; static final String PARENT_ID_KEY = "parent_id"; + static final String LINK_ID_KEY = "link_id"; static final String ERRORS_KEY = "errors"; static final String ARGS_KEY = "args"; static final String FIELDS_KEY = "fields"; diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java index cb6b8acc..2edb526e 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ParseComment.java @@ -215,6 +215,8 @@ class ParseComment { String id = singleCommentData.getString(JSONUtils.ID_KEY); String fullName = singleCommentData.getString(JSONUtils.NAME_KEY); String author = singleCommentData.getString(JSONUtils.AUTHOR_KEY); + String linkId = singleCommentData.getString(JSONUtils.LINK_ID_KEY).substring(3); + String subredditName = singleCommentData.getString(JSONUtils.SUBREDDIT_KEY); String parentId = singleCommentData.getString(JSONUtils.PARENT_ID_KEY); boolean isSubmitter = singleCommentData.getBoolean(JSONUtils.IS_SUBMITTER_KEY); String commentContent = ""; @@ -238,7 +240,7 @@ class ParseComment { boolean collapsed = singleCommentData.getBoolean(JSONUtils.COLLAPSED_KEY); boolean hasReply = !(singleCommentData.get(JSONUtils.REPLIES_KEY) instanceof String); - return new CommentData(id, fullName, author, formattedSubmitTime, commentContent, parentId, score, - isSubmitter, permalink, depth, collapsed, hasReply, scoreHidden); + return new CommentData(id, fullName, author, formattedSubmitTime, commentContent, linkId, + subredditName, parentId, score, isSubmitter, permalink, depth, collapsed, hasReply, scoreHidden); } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java index 2f5c882e..09d5451a 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/PostDataSource.java @@ -155,7 +155,11 @@ class PostDataSource extends PageKeyedDataSource { onPostFetchedCallback.hasPost(); } - callback.onResult(newPosts, null, lastItem); + if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) { + callback.onResult(newPosts, null, null); + } else { + callback.onResult(newPosts, null, lastItem); + } initialLoadStateLiveData.postValue(NetworkState.LOADED); } @@ -235,7 +239,11 @@ class PostDataSource extends PageKeyedDataSource { onPostFetchedCallback.hasPost(); } - callback.onResult(newPosts, null, lastItem); + if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) { + callback.onResult(newPosts, null, null); + } else { + callback.onResult(newPosts, null, lastItem); + } initialLoadStateLiveData.postValue(NetworkState.LOADED); } @@ -308,17 +316,18 @@ class PostDataSource extends PageKeyedDataSource { new ParsePost.ParsePostsListingListener() { @Override public void onParsePostsListingSuccess(ArrayList newPosts, String lastItem) { - if(newPosts.size() == 0 && lastItem.equals("null")) { - callback.onResult(newPosts, null, lastItem); - initialLoadStateLiveData.postValue(NetworkState.LOADED); + if(newPosts.size() == 0) { onPostFetchedCallback.noPost(); - } else if(newPosts.size() == 0) { - loadUserPostsInitial(callback, lastItem); } else { - callback.onResult(newPosts, null, lastItem); - initialLoadStateLiveData.postValue(NetworkState.LOADED); onPostFetchedCallback.hasPost(); } + + if(lastItem == null || lastItem.equals("") || lastItem.equals("null")) { + callback.onResult(newPosts, null, null); + } else { + callback.onResult(newPosts, null, lastItem); + } + initialLoadStateLiveData.postValue(NetworkState.LOADED); } @Override diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java index d8a86141..9ad7d23d 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RedditAPI.java @@ -101,6 +101,9 @@ public interface RedditAPI { @GET("/r/{subredditName}/about/rules.json?raw_json=1") Call getRules(@Path("subredditName") String subredditName); + @GET("/comments/{id}.json?raw_json=1") + Call getPostAndCommentsById(@Path("id") String id, @HeaderMap Map headers); + @Multipart @POST(".") Call uploadMediaToAWS(@PartMap()Map params, @Part() MultipartBody.Part file); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index f605666c..8d67cd7c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -6,6 +6,11 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; @@ -31,6 +36,9 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; import retrofit2.Retrofit; import static ml.docilealligator.infinityforreddit.CommentActivity.EXTRA_COMMENT_DATA_KEY; @@ -40,6 +48,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { static final String EXTRA_POST_DATA = "EPD"; static final String EXTRA_POST_LIST_POSITION = "EPLI"; + static final String EXTRA_POST_ID = "EPI"; private RequestManager mGlide; private Locale mLocale; @@ -70,7 +79,11 @@ public class ViewPostDetailActivity extends AppCompatActivity { @BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout; @BindView(R.id.toolbar_view_post_detail_activity) Toolbar toolbar; + @BindView(R.id.progress_bar_view_post_detail_activity) ProgressBar mProgressBar; @BindView(R.id.recycler_view_view_post_detail) RecyclerView mRecyclerView; + @BindView(R.id.fetch_post_info_linear_layout_view_post_detail_activity) LinearLayout mFetchPostInfoLinearLayout; + @BindView(R.id.fetch_post_info_image_view_view_post_detail_activity) ImageView mFetchPostInfoImageView; + @BindView(R.id.fetch_post_info_text_view_view_post_detail_activity) TextView mFetchPostInfoTextView; @Inject @Named("no_oauth") Retrofit mRetrofit; @@ -109,43 +122,48 @@ public class ViewPostDetailActivity extends AppCompatActivity { mPost = savedInstanceState.getParcelable(POST_STATE); } - mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, - mOauthRetrofit, mGlide, mSharedPreferences, mPost, - mPost.getSubredditNamePrefixed(), mLocale, mLoadSubredditIconAsyncTask, - new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { - @Override - public void updatePost(Post post) { - EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); - } + if(mPost == null) { + mProgressBar.setVisibility(View.VISIBLE); + fetchPostAndCommentsById(getIntent().getExtras().getString(EXTRA_POST_ID)); + } else { + mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, + mOauthRetrofit, mGlide, mSharedPreferences, mPost, + mPost.getSubredditNamePrefixed(), mLocale, mLoadSubredditIconAsyncTask, + new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { + @Override + public void updatePost(Post post) { + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } - @Override - public void retryFetchingMoreComments() { + @Override + public void retryFetchingMoreComments() { + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = true; + + fetchMoreComments(); + } + }); + mRecyclerView.setAdapter(mAdapter); + + if(savedInstanceState != null) { + isRefreshing = savedInstanceState.getBoolean(IS_REFRESHING_STATE); + if(isRefreshing) { + isRefreshing = false; + refresh(); + } else { + mAdapter.addComments(savedInstanceState.getParcelableArrayList(COMMENTS_STATE), + savedInstanceState.getBoolean(HAS_MORE_CHILDREN_STATE)); + isLoadingMoreChildren = savedInstanceState.getBoolean(IS_LOADING_MORE_CHILDREN_STATE); + children = savedInstanceState.getStringArrayList(MORE_CHILDREN_LIST_STATE); + mChildrenStartingIndex = savedInstanceState.getInt(MORE_CHILDREN_STARTING_INDEX_STATE); + if(isLoadingMoreChildren) { isLoadingMoreChildren = false; - loadMoreChildrenSuccess = true; - fetchMoreComments(); } - }); - mRecyclerView.setAdapter(mAdapter); - - if(savedInstanceState != null) { - isRefreshing = savedInstanceState.getBoolean(IS_REFRESHING_STATE); - if(isRefreshing) { - isRefreshing = false; - refresh(); - } else { - mAdapter.addComments(savedInstanceState.getParcelableArrayList(COMMENTS_STATE), - savedInstanceState.getBoolean(HAS_MORE_CHILDREN_STATE)); - isLoadingMoreChildren = savedInstanceState.getBoolean(IS_LOADING_MORE_CHILDREN_STATE); - children = savedInstanceState.getStringArrayList(MORE_CHILDREN_LIST_STATE); - mChildrenStartingIndex = savedInstanceState.getInt(MORE_CHILDREN_STARTING_INDEX_STATE); - if(isLoadingMoreChildren) { - isLoadingMoreChildren = false; - fetchMoreComments(); } + } else { + fetchComment(); } - } else { - fetchComment(); } if(getIntent().hasExtra(EXTRA_POST_LIST_POSITION)) { @@ -153,6 +171,98 @@ public class ViewPostDetailActivity extends AppCompatActivity { } } + private void fetchPostAndCommentsById(String subredditId) { + mFetchPostInfoLinearLayout.setVisibility(View.GONE); + mGlide.clear(mFetchPostInfoImageView); + + String accessToken = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) + .getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + + RedditAPI api = mOauthRetrofit.create(RedditAPI.class); + Call postAndComments = api.getPostAndCommentsById(subredditId, RedditUtils.getOAuthHeader(accessToken)); + postAndComments.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + mProgressBar.setVisibility(View.GONE); + + if(response.isSuccessful()) { + ParsePost.parsePost(response.body(), mLocale, new ParsePost.ParsePostListener() { + @Override + public void onParsePostSuccess(Post post) { + mPost = post; + + mAdapter = new CommentAndPostRecyclerViewAdapter(ViewPostDetailActivity.this, mRetrofit, + mOauthRetrofit, mGlide, mSharedPreferences, mPost, + mPost.getSubredditNamePrefixed(), mLocale, mLoadSubredditIconAsyncTask, + new CommentAndPostRecyclerViewAdapter.CommentRecyclerViewAdapterCallback() { + @Override + public void updatePost(Post post) { + EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); + } + + @Override + public void retryFetchingMoreComments() { + isLoadingMoreChildren = false; + loadMoreChildrenSuccess = true; + + fetchMoreComments(); + } + }); + mRecyclerView.setAdapter(mAdapter); + + ParseComment.parseComment(response.body(), new ArrayList<>(), mLocale, + new ParseComment.ParseCommentListener() { + @Override + public void onParseCommentSuccess(ArrayList expandedComments, String parentId, ArrayList moreChildrenFullnames) { + ViewPostDetailActivity.this.children = moreChildrenFullnames; + + hasMoreChildren = children.size() != 0; + mAdapter.addComments(expandedComments, hasMoreChildren); + + if(children.size() > 0) { + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + + if(!isLoadingMoreChildren && loadMoreChildrenSuccess) { + int visibleItemCount = mLinearLayoutManager.getChildCount(); + int totalItemCount = mLinearLayoutManager.getItemCount(); + int firstVisibleItemPosition = mLinearLayoutManager.findFirstVisibleItemPosition(); + + if ((visibleItemCount + firstVisibleItemPosition >= totalItemCount) && firstVisibleItemPosition >= 0) { + fetchMoreComments(); + } + } + } + }); + } + } + + @Override + public void onParseCommentFailed() { + mAdapter.initiallyLoadCommentsFailed(); + } + }); + } + + @Override + public void onParsePostFail() { + showErrorView(subredditId); + } + }); + } else { + showErrorView(subredditId); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + showErrorView(subredditId); + } + }); + } + private void fetchComment() { mAdapter.initiallyLoading(); @@ -224,6 +334,9 @@ public class ViewPostDetailActivity extends AppCompatActivity { isRefreshing = true; mChildrenStartingIndex = 0; + mFetchPostInfoLinearLayout.setVisibility(View.GONE); + mGlide.clear(mFetchPostInfoImageView); + fetchComment(); String accessToken = getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE) @@ -247,6 +360,14 @@ public class ViewPostDetailActivity extends AppCompatActivity { } } + private void showErrorView(String subredditId) { + mProgressBar.setVisibility(View.GONE); + mFetchPostInfoLinearLayout.setVisibility(View.VISIBLE); + mFetchPostInfoLinearLayout.setOnClickListener(view -> fetchPostAndCommentsById(subredditId)); + mFetchPostInfoTextView.setText(R.string.error_loading_post); + mGlide.load(R.drawable.load_post_error_indicator).into(mFetchPostInfoImageView); + } + @Subscribe public void onPostUpdateEvent(PostUpdateEventToDetailActivity event) { if(mPost.getId().equals(event.postId)) { diff --git a/app/src/main/res/layout/activity_view_post_detail.xml b/app/src/main/res/layout/activity_view_post_detail.xml index 7416ed7a..11f5ce1e 100644 --- a/app/src/main/res/layout/activity_view_post_detail.xml +++ b/app/src/main/res/layout/activity_view_post_detail.xml @@ -21,10 +21,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_view_user_detail.xml b/app/src/main/res/layout/activity_view_user_detail.xml index 67beecd2..bbdf6603 100644 --- a/app/src/main/res/layout/activity_view_user_detail.xml +++ b/app/src/main/res/layout/activity_view_user_detail.xml @@ -10,7 +10,7 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_comment.xml b/app/src/main/res/layout/item_comment.xml index d03b0bad..d949904a 100644 --- a/app/src/main/res/layout/item_comment.xml +++ b/app/src/main/res/layout/item_comment.xml @@ -1,5 +1,6 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76e3f626..5d8904e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -131,4 +131,6 @@ Search in All subreddits + + Error loading this post.\nTap to retry.