Click a comment to view the corresponding post.

This commit is contained in:
Alex Ning 2019-07-22 11:13:57 +08:00
parent 2f15543f91
commit fcff7784c9
11 changed files with 259 additions and 54 deletions

View File

@ -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);

View File

@ -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<CommentData, R
private Context mContext;
private Retrofit mOauthRetrofit;
private SharedPreferences mSharedPreferences;
private int textColorPrimaryDark;
private int colorAccent;
private static final int VIEW_TYPE_DATA = 0;
private static final int VIEW_TYPE_ERROR = 1;
@ -46,6 +50,8 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter<CommentData, R
mOauthRetrofit = oauthRetrofit;
mSharedPreferences = sharedPreferences;
mRetryLoadingMoreCallback = retryLoadingMoreCallback;
textColorPrimaryDark = mContext.getResources().getColor(R.color.textColorPrimaryDark);
colorAccent = mContext.getResources().getColor(R.color.colorAccent);
}
private static final DiffUtil.ItemCallback<CommentData> DIFF_CALLBACK = new DiffUtil.ItemCallback<CommentData>() {
@ -80,8 +86,23 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter<CommentData, R
if(holder instanceof DataViewHolder) {
CommentData comment = getItem(holder.getAdapterPosition());
String authorPrefixed = "u/" + comment.getAuthor();
((DataViewHolder) holder).authorTextView.setText(authorPrefixed);
if(comment.getAuthor().equals(comment.getSubredditName().substring(2))) {
((DataViewHolder) holder).authorTextView.setText("u/" + comment.getAuthor());
((DataViewHolder) holder).authorTextView.setTextColor(textColorPrimaryDark);
((DataViewHolder) holder).authorTextView.setOnClickListener(view -> {
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<CommentData, R
}
class DataViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.card_view_item_comment) MaterialCardView cardView;
@BindView(R.id.vertical_block_item_post_comment) View verticalBlock;
@BindView(R.id.author_text_view_item_post_comment) TextView authorTextView;
@BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView;
@ -158,14 +180,16 @@ class CommentsListingRecyclerViewAdapter extends PagedListAdapter<CommentData, R
super(itemView);
ButterKnife.bind(this, itemView);
verticalBlock.setVisibility(View.GONE);
authorTextView.setOnClickListener(view -> {
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);

View File

@ -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";

View File

@ -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);
}
}

View File

@ -155,7 +155,11 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
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<String, Post> {
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<String, Post> {
new ParsePost.ParsePostsListingListener() {
@Override
public void onParsePostsListingSuccess(ArrayList<Post> 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

View File

@ -101,6 +101,9 @@ public interface RedditAPI {
@GET("/r/{subredditName}/about/rules.json?raw_json=1")
Call<String> getRules(@Path("subredditName") String subredditName);
@GET("/comments/{id}.json?raw_json=1")
Call<String> getPostAndCommentsById(@Path("id") String id, @HeaderMap Map<String, String> headers);
@Multipart
@POST(".")
Call<String> uploadMediaToAWS(@PartMap()Map<String, RequestBody> params, @Part() MultipartBody.Part file);

View File

@ -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<String> postAndComments = api.getPostAndCommentsById(subredditId, RedditUtils.getOAuthHeader(accessToken));
postAndComments.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> 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<CommentData> expandedComments, String parentId, ArrayList<String> 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<String> 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)) {

View File

@ -21,10 +21,38 @@
</com.google.android.material.appbar.AppBarLayout>
<ProgressBar
android:id="@+id/progress_bar_view_post_detail_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_view_post_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:id="@+id/fetch_post_info_linear_layout_view_post_detail_activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:id="@+id/fetch_post_info_image_view_view_post_detail_activity"
android:layout_width="150dp"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fetch_post_info_text_view_view_post_detail_activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -10,7 +10,7 @@
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager_view_user_detail_activity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<com.google.android.material.appbar.AppBarLayout
@ -114,6 +114,4 @@
</com.google.android.material.appbar.AppBarLayout>
<!--<include layout="@layout/content_view_user_detail" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_view_item_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content">

View File

@ -131,4 +131,6 @@
<string name="search_in">Search in</string>
<string name="all_subreddits">All subreddits</string>
<string name="error_loading_post">Error loading this post.\nTap to retry.</string>
</resources>