mirror of
https://codeberg.org/Bazsalanszky/Infinity-For-Lemmy.git
synced 2025-03-28 04:15:29 +01:00
Load All comments of a post using paging library. Loading comments of comments is now broken.
This commit is contained in:
parent
0e1abee883
commit
0d6296c1a4
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
BIN
.idea/caches/gradle_models.ser
generated
BIN
.idea/caches/gradle_models.ser
generated
Binary file not shown.
@ -59,7 +59,7 @@ dependencies {
|
|||||||
annotationProcessor "android.arch.lifecycle:compiler:$rootProject.archLifecycleVersion"
|
annotationProcessor "android.arch.lifecycle:compiler:$rootProject.archLifecycleVersion"
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||||
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
|
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
||||||
implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
|
implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
|
||||||
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||||
implementation 'com.muditsen.multilevelrecyclerview:multilevelview:1.0.0'
|
implementation 'com.muditsen.multilevelrecyclerview:multilevelview:1.0.0'
|
||||||
|
@ -0,0 +1,343 @@
|
|||||||
|
package ml.docilealligator.infinityforreddit;
|
||||||
|
|
||||||
|
import android.arch.paging.PagedListAdapter;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.ColorFilter;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.customtabs.CustomTabsIntent;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
|
import android.support.v7.util.DiffUtil;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.multilevelview.models.RecyclerViewItem;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import ru.noties.markwon.SpannableConfiguration;
|
||||||
|
import ru.noties.markwon.view.MarkwonView;
|
||||||
|
|
||||||
|
public class CommentAdapter extends PagedListAdapter<CommentData, RecyclerView.ViewHolder> {
|
||||||
|
private Context mContext;
|
||||||
|
private Retrofit mRetrofit;
|
||||||
|
private Retrofit mOauthRetrofit;
|
||||||
|
private SharedPreferences mSharedPreferences;
|
||||||
|
private RecyclerView mRecyclerView;
|
||||||
|
private String subredditNamePrefixed;
|
||||||
|
private String article;
|
||||||
|
private Locale locale;
|
||||||
|
|
||||||
|
private NetworkState networkState;
|
||||||
|
private RetryLoadingMoreCallback retryLoadingMoreCallback;
|
||||||
|
|
||||||
|
interface RetryLoadingMoreCallback {
|
||||||
|
void retryLoadingMore();
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentAdapter(Context context, Retrofit retrofit, Retrofit oauthRetrofit,
|
||||||
|
SharedPreferences sharedPreferences, RecyclerView recyclerView,
|
||||||
|
String subredditNamePrefixed, String article, Locale locale) {
|
||||||
|
super(DIFF_CALLBACK);
|
||||||
|
mContext = context;
|
||||||
|
mRetrofit = retrofit;
|
||||||
|
mOauthRetrofit = oauthRetrofit;
|
||||||
|
mSharedPreferences = sharedPreferences;
|
||||||
|
mRecyclerView = recyclerView;
|
||||||
|
this.subredditNamePrefixed = subredditNamePrefixed;
|
||||||
|
this.article = article;
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final DiffUtil.ItemCallback<CommentData> DIFF_CALLBACK = new DiffUtil.ItemCallback<CommentData>() {
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(@NonNull CommentData commentData, @NonNull CommentData t1) {
|
||||||
|
return commentData.getId().equals(t1.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(@NonNull CommentData commentData, @NonNull CommentData t1) {
|
||||||
|
return commentData.getCommentContent().equals(t1.getCommentContent());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int i) {
|
||||||
|
return new CommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_post_comment, parent, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
|
||||||
|
final CommentData commentItem = getItem(i);
|
||||||
|
|
||||||
|
String authorPrefixed = "u/" + commentItem.getAuthor();
|
||||||
|
((CommentViewHolder) viewHolder).authorTextView.setText(authorPrefixed);
|
||||||
|
((CommentViewHolder) viewHolder).authorTextView.setOnClickListener(view -> {
|
||||||
|
Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
|
||||||
|
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, commentItem.getAuthor());
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
});
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).commentTimeTextView.setText(commentItem.getCommentTime());
|
||||||
|
SpannableConfiguration spannableConfiguration = SpannableConfiguration.builder(mContext).linkResolver((view, link) -> {
|
||||||
|
if(link.startsWith("/u/")) {
|
||||||
|
Intent intent = new Intent(mContext, ViewUserDetailActivity.class);
|
||||||
|
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, link.substring(3));
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
} else if(link.startsWith("/r/")) {
|
||||||
|
Intent intent = new Intent(mContext, ViewSubredditDetailActivity.class);
|
||||||
|
intent.putExtra(ViewSubredditDetailActivity.EXTRA_SUBREDDIT_NAME_KEY, link.substring(3));
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
} else {
|
||||||
|
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||||
|
// add share action to menu list
|
||||||
|
builder.addDefaultShareMenuItem();
|
||||||
|
builder.setToolbarColor(mContext.getResources().getColor(R.color.colorPrimary));
|
||||||
|
CustomTabsIntent customTabsIntent = builder.build();
|
||||||
|
customTabsIntent.launchUrl(mContext, Uri.parse(link));
|
||||||
|
}
|
||||||
|
}).build();
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).commentMarkdownView.setMarkdown(spannableConfiguration, commentItem.getCommentContent());
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).verticalBlock.getLayoutParams().width = commentItem.getDepth() * 16;
|
||||||
|
if(commentItem.hasReply()) {
|
||||||
|
setExpandButton(((CommentViewHolder) viewHolder).expandButton, commentItem.isExpanded());
|
||||||
|
}
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).expandButton.setOnClickListener(view -> {
|
||||||
|
if(commentItem.hasChildren() && commentItem.getChildren().size() > 0) {
|
||||||
|
//mRecyclerView.toggleItemsGroup(viewHolder.getAdapterPosition());
|
||||||
|
setExpandButton(((CommentViewHolder) viewHolder).expandButton, commentItem.isExpanded());
|
||||||
|
} else {
|
||||||
|
((CommentViewHolder) viewHolder).loadMoreCommentsProgressBar.setVisibility(View.VISIBLE);
|
||||||
|
FetchComment.fetchComment(mRetrofit, subredditNamePrefixed, article, commentItem.getId(),
|
||||||
|
new FetchComment.FetchCommentListener() {
|
||||||
|
@Override
|
||||||
|
public void onFetchCommentSuccess(String response) {
|
||||||
|
ParseComment.parseComment(response, new ArrayList<CommentData>(),
|
||||||
|
locale, false, commentItem.getDepth(), 1,
|
||||||
|
new ParseComment.ParseCommentListener() {
|
||||||
|
@Override
|
||||||
|
public void onParseCommentSuccess(List<?> commentData,
|
||||||
|
String parentId, String commaSeparatedChildren) {
|
||||||
|
commentItem.addChildren((List<RecyclerViewItem>) commentData);
|
||||||
|
((CommentViewHolder) viewHolder).loadMoreCommentsProgressBar
|
||||||
|
.setVisibility(View.GONE);
|
||||||
|
//mRecyclerView.toggleItemsGroup(viewHolder.getAdapterPosition());
|
||||||
|
((CommentViewHolder) viewHolder).expandButton
|
||||||
|
.setImageResource(R.drawable.ic_expand_less_black_20dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParseCommentFailed() {
|
||||||
|
((CommentViewHolder) viewHolder).loadMoreCommentsProgressBar
|
||||||
|
.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFetchCommentFail() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (commentItem.getVoteType()) {
|
||||||
|
case 1:
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton
|
||||||
|
.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton
|
||||||
|
.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.setOnClickListener(view -> {
|
||||||
|
final boolean isDownvotedBefore = ((CommentViewHolder) viewHolder).downvoteButton.getColorFilter() != null;
|
||||||
|
final ColorFilter minusButtonColorFilter = ((CommentViewHolder) viewHolder).downvoteButton.getColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.clearColorFilter();
|
||||||
|
|
||||||
|
if (((CommentViewHolder) viewHolder).upvoteButton.getColorFilter() == null) {
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
if(isDownvotedBefore) {
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 2));
|
||||||
|
} else {
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
VoteThing.voteThing(mOauthRetrofit,mSharedPreferences, new VoteThing.VoteThingListener() {
|
||||||
|
@Override
|
||||||
|
public void onVoteThingSuccess(int position1) {
|
||||||
|
commentItem.setVoteType(1);
|
||||||
|
if(isDownvotedBefore) {
|
||||||
|
commentItem.setScore(commentItem.getScore() + 2);
|
||||||
|
} else {
|
||||||
|
commentItem.setScore(commentItem.getScore() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoteThingFail(int position1) {
|
||||||
|
Toast.makeText(mContext, "Cannot upvote this comment", Toast.LENGTH_SHORT).show();
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.clearColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.setColorFilter(minusButtonColorFilter);
|
||||||
|
}
|
||||||
|
}, commentItem.getFullName(), RedditUtils.DIR_UPVOTE, ((CommentViewHolder) viewHolder).getAdapterPosition());
|
||||||
|
} else {
|
||||||
|
//Upvoted before
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.clearColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1));
|
||||||
|
|
||||||
|
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
|
||||||
|
@Override
|
||||||
|
public void onVoteThingSuccess(int position1) {
|
||||||
|
commentItem.setVoteType(0);
|
||||||
|
commentItem.setScore(commentItem.getScore() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoteThingFail(int position1) {
|
||||||
|
Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show();
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1));
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
commentItem.setScore(commentItem.getScore() + 1);
|
||||||
|
}
|
||||||
|
}, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, ((CommentViewHolder) viewHolder).getAdapterPosition());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.setOnClickListener(view -> {
|
||||||
|
final boolean isUpvotedBefore = ((CommentViewHolder) viewHolder).upvoteButton.getColorFilter() != null;
|
||||||
|
|
||||||
|
final ColorFilter upvoteButtonColorFilter = ((CommentViewHolder) viewHolder).upvoteButton.getColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.clearColorFilter();
|
||||||
|
|
||||||
|
if (((CommentViewHolder) viewHolder).downvoteButton.getColorFilter() == null) {
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
if (isUpvotedBefore) {
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 2));
|
||||||
|
} else {
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
|
||||||
|
@Override
|
||||||
|
public void onVoteThingSuccess(int position12) {
|
||||||
|
commentItem.setVoteType(-1);
|
||||||
|
if(isUpvotedBefore) {
|
||||||
|
commentItem.setScore(commentItem.getScore() - 2);
|
||||||
|
} else {
|
||||||
|
commentItem.setScore(commentItem.getScore() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoteThingFail(int position12) {
|
||||||
|
Toast.makeText(mContext, "Cannot downvote this comment", Toast.LENGTH_SHORT).show();
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.clearColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
|
||||||
|
((CommentViewHolder) viewHolder).upvoteButton.setColorFilter(upvoteButtonColorFilter);
|
||||||
|
}
|
||||||
|
}, commentItem.getFullName(), RedditUtils.DIR_DOWNVOTE, viewHolder.getAdapterPosition());
|
||||||
|
} else {
|
||||||
|
//Down voted before
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.clearColorFilter();
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore() + 1));
|
||||||
|
|
||||||
|
VoteThing.voteThing(mOauthRetrofit, mSharedPreferences, new VoteThing.VoteThingListener() {
|
||||||
|
@Override
|
||||||
|
public void onVoteThingSuccess(int position12) {
|
||||||
|
commentItem.setVoteType(0);
|
||||||
|
commentItem.setScore(commentItem.getScore());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoteThingFail(int position12) {
|
||||||
|
Toast.makeText(mContext, "Cannot unvote this comment", Toast.LENGTH_SHORT).show();
|
||||||
|
((CommentViewHolder) viewHolder).downvoteButton.setColorFilter(ContextCompat.getColor(mContext, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN);
|
||||||
|
((CommentViewHolder) viewHolder).scoreTextView.setText(Integer.toString(commentItem.getScore()));
|
||||||
|
commentItem.setScore(commentItem.getScore());
|
||||||
|
}
|
||||||
|
}, commentItem.getFullName(), RedditUtils.DIR_UNVOTE, viewHolder.getAdapterPosition());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
|
||||||
|
((CommentMultiLevelRecyclerViewAdapter.CommentViewHolder) holder).expandButton.setVisibility(View.GONE);
|
||||||
|
((CommentMultiLevelRecyclerViewAdapter.CommentViewHolder) holder).loadMoreCommentsProgressBar.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if(hasExtraRow()) {
|
||||||
|
return super.getItemCount() + 1;
|
||||||
|
}
|
||||||
|
return super.getItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasExtraRow() {
|
||||||
|
return networkState != null && networkState.getStatus() != NetworkState.Status.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNetworkState(NetworkState newNetworkState) {
|
||||||
|
NetworkState previousState = this.networkState;
|
||||||
|
boolean previousExtraRow = hasExtraRow();
|
||||||
|
this.networkState = newNetworkState;
|
||||||
|
boolean newExtraRow = hasExtraRow();
|
||||||
|
if (previousExtraRow != newExtraRow) {
|
||||||
|
if (previousExtraRow) {
|
||||||
|
notifyItemRemoved(super.getItemCount());
|
||||||
|
} else {
|
||||||
|
notifyItemInserted(super.getItemCount());
|
||||||
|
}
|
||||||
|
} else if (newExtraRow && !previousState.equals(newNetworkState)) {
|
||||||
|
notifyItemChanged(getItemCount() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setExpandButton(ImageView expandButton, boolean isExpanded) {
|
||||||
|
// set the icon based on the current state
|
||||||
|
expandButton.setVisibility(View.VISIBLE);
|
||||||
|
expandButton.setImageResource(isExpanded ? R.drawable.ic_expand_less_black_20dp : R.drawable.ic_expand_more_black_20dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommentViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
@BindView(R.id.author_text_view_item_post_comment) TextView authorTextView;
|
||||||
|
@BindView(R.id.comment_time_text_view_item_post_comment) TextView commentTimeTextView;
|
||||||
|
@BindView(R.id.comment_markdown_view_item_post_comment) MarkwonView commentMarkdownView;
|
||||||
|
@BindView(R.id.plus_button_item_post_comment) ImageView upvoteButton;
|
||||||
|
@BindView(R.id.score_text_view_item_post_comment) TextView scoreTextView;
|
||||||
|
@BindView(R.id.minus_button_item_post_comment) ImageView downvoteButton;
|
||||||
|
@BindView(R.id.expand_button_item_post_comment) ImageView expandButton;
|
||||||
|
@BindView(R.id.load_more_comments_progress_bar) ProgressBar loadMoreCommentsProgressBar;
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,195 @@
|
|||||||
|
package ml.docilealligator.infinityforreddit;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
|
import android.arch.paging.PageKeyedDataSource;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
|
||||||
|
public class CommentDataSource extends PageKeyedDataSource<String, Post> {
|
||||||
|
interface OnCommentFetchedCallback {
|
||||||
|
void hasComment();
|
||||||
|
void noComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Retrofit retrofit;
|
||||||
|
private Locale locale;
|
||||||
|
private String subredditNamePrefixed;
|
||||||
|
private String article;
|
||||||
|
private String comment;
|
||||||
|
private boolean isPost;
|
||||||
|
private OnCommentFetchedCallback onCommentFetchedCallback;
|
||||||
|
|
||||||
|
private MutableLiveData<NetworkState> paginationNetworkStateLiveData;
|
||||||
|
private MutableLiveData<NetworkState> initialLoadStateLiveData;
|
||||||
|
|
||||||
|
private LoadInitialParams<String> initialParams;
|
||||||
|
private LoadInitialCallback<String, Post> initialCallback;
|
||||||
|
private LoadParams<String> params;
|
||||||
|
private LoadCallback<String, Post> callback;
|
||||||
|
|
||||||
|
private String mParentId;
|
||||||
|
|
||||||
|
CommentDataSource(Retrofit retrofit, Locale locale, String subredditNamePrefixed, String article,
|
||||||
|
String comment, boolean isPost, OnCommentFetchedCallback onCommentFetchedCallback) {
|
||||||
|
this.retrofit = retrofit;
|
||||||
|
this.locale = locale;
|
||||||
|
this.subredditNamePrefixed = subredditNamePrefixed;
|
||||||
|
this.article = article;
|
||||||
|
this.comment = comment;
|
||||||
|
this.isPost = isPost;
|
||||||
|
paginationNetworkStateLiveData = new MutableLiveData();
|
||||||
|
initialLoadStateLiveData = new MutableLiveData();
|
||||||
|
this.onCommentFetchedCallback = onCommentFetchedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableLiveData getPaginationNetworkStateLiveData() {
|
||||||
|
return paginationNetworkStateLiveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutableLiveData getInitialLoadStateLiveData() {
|
||||||
|
return initialLoadStateLiveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadInitial(@NonNull LoadInitialParams<String> params, @NonNull LoadInitialCallback<String, Post> callback) {
|
||||||
|
initialParams = params;
|
||||||
|
initialCallback = callback;
|
||||||
|
|
||||||
|
initialLoadStateLiveData.postValue(NetworkState.LOADING);
|
||||||
|
|
||||||
|
RedditAPI api = retrofit.create(RedditAPI.class);
|
||||||
|
|
||||||
|
Call<String> comments = api.getComments(subredditNamePrefixed, article, comment);
|
||||||
|
comments.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
|
||||||
|
if(response.isSuccessful()) {
|
||||||
|
ParseComment.parseComment(response.body(), new ArrayList<>(), locale, isPost,
|
||||||
|
0, 1, new ParseComment.ParseCommentListener() {
|
||||||
|
@Override
|
||||||
|
public void onParseCommentSuccess(List<?> commentData, String parentId,
|
||||||
|
String commaSeparatedChildren) {
|
||||||
|
if(commentData.size() > 0) {
|
||||||
|
onCommentFetchedCallback.hasComment();
|
||||||
|
mParentId = parentId;
|
||||||
|
} else {
|
||||||
|
onCommentFetchedCallback.noComment();
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.onResult((List<Post>) commentData, null, commaSeparatedChildren);
|
||||||
|
initialLoadStateLiveData.postValue(NetworkState.LOADED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParseCommentFailed() {
|
||||||
|
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing comment"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.i("comment call failed", response.message());
|
||||||
|
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing comment"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
|
||||||
|
initialLoadStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error fetching comment"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadBefore(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, Post> callback) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadAfter(@NonNull LoadParams<String> params, @NonNull LoadCallback<String, Post> callback) {
|
||||||
|
this.params = params;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
if(params.key.equals("null") || params.key.equals("")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paginationNetworkStateLiveData.postValue(NetworkState.LOADING);
|
||||||
|
|
||||||
|
RedditAPI api = retrofit.create(RedditAPI.class);
|
||||||
|
|
||||||
|
Call<String> moreChildrenBasicInfo = api.getMoreChildren(mParentId, params.key);
|
||||||
|
moreChildrenBasicInfo.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if(response.isSuccessful()) {
|
||||||
|
ParseComment.parseMoreCommentBasicInfo(response.body(), new ParseComment.ParseMoreCommentBasicInfoListener() {
|
||||||
|
@Override
|
||||||
|
public void onParseMoreCommentBasicInfoSuccess(String commaSeparatedChildrenId) {
|
||||||
|
Call<String> moreComments = api.getInfo(subredditNamePrefixed, commaSeparatedChildrenId);
|
||||||
|
moreComments.enqueue(new Callback<String>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<String> call, Response<String> response) {
|
||||||
|
if(response.isSuccessful()) {
|
||||||
|
ParseComment.parseMoreComment(response.body(), new ArrayList<>(), locale, isPost,
|
||||||
|
0, 0, new ParseComment.ParseCommentListener() {
|
||||||
|
@Override
|
||||||
|
public void onParseCommentSuccess(List<?> commentData, String parentId,
|
||||||
|
String commaSeparatedChildren) {
|
||||||
|
callback.onResult((List<Post>) commentData, null);
|
||||||
|
paginationNetworkStateLiveData.postValue(NetworkState.LOADED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParseCommentFailed() {
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Error parsing data"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.i("comment call failed", response.message());
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
String errorMessage = t == null ? "unknown error" : t.getMessage();
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onParseMoreCommentBasicInfoFailed() {
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, "Parse more comments basic info failed"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.i("comment call failed", response.message());
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, response.message()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<String> call, Throwable t) {
|
||||||
|
String errorMessage = t == null ? "unknown error" : t.getMessage();
|
||||||
|
paginationNetworkStateLiveData.postValue(new NetworkState(NetworkState.Status.FAILED, errorMessage));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void retry() {
|
||||||
|
loadInitial(initialParams, initialCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void retryLoadingMore() {
|
||||||
|
loadAfter(params, callback);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package ml.docilealligator.infinityforreddit;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.MutableLiveData;
|
||||||
|
import android.arch.paging.DataSource;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
|
||||||
|
public class CommentDataSourceFactory extends DataSource.Factory {
|
||||||
|
private Retrofit retrofit;
|
||||||
|
private Locale locale;
|
||||||
|
private String subredditNamePrefixed;
|
||||||
|
private String article;
|
||||||
|
private String comment;
|
||||||
|
private boolean isPost;
|
||||||
|
private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
|
||||||
|
|
||||||
|
private CommentDataSource commentDataSource;
|
||||||
|
private MutableLiveData<CommentDataSource> commentDataSourceMutableLiveData;
|
||||||
|
|
||||||
|
CommentDataSourceFactory(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
|
||||||
|
String article, String comment, boolean isPost,
|
||||||
|
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
|
||||||
|
this.retrofit = retrofit;
|
||||||
|
this.locale = locale;
|
||||||
|
this.subredditNamePrefixed = subredditNamePrefixed;
|
||||||
|
this.article = article;
|
||||||
|
this.comment = comment;
|
||||||
|
this.isPost = isPost;
|
||||||
|
commentDataSourceMutableLiveData = new MutableLiveData<>();
|
||||||
|
this.onCommentFetchedCallback = onCommentFetchedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSource create() {
|
||||||
|
commentDataSource = new CommentDataSource(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
|
||||||
|
commentDataSourceMutableLiveData.postValue(commentDataSource);
|
||||||
|
return commentDataSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableLiveData<CommentDataSource> getCommentDataSourceMutableLiveData() {
|
||||||
|
return commentDataSourceMutableLiveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentDataSource getCommentDataSource() {
|
||||||
|
return commentDataSource;
|
||||||
|
}
|
||||||
|
}
|
@ -115,9 +115,11 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
|
|||||||
@Override
|
@Override
|
||||||
public void onFetchCommentSuccess(String response) {
|
public void onFetchCommentSuccess(String response) {
|
||||||
ParseComment.parseComment(response, new ArrayList<CommentData>(),
|
ParseComment.parseComment(response, new ArrayList<CommentData>(),
|
||||||
locale, false, commentItem.getDepth(), new ParseComment.ParseCommentListener() {
|
locale, false, commentItem.getDepth(), 1,
|
||||||
|
new ParseComment.ParseCommentListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onParseCommentSuccess(List<?> commentData, int moreCommentCount) {
|
public void onParseCommentSuccess(List<?> commentData,
|
||||||
|
String parentId, String commaSeparatedChildren) {
|
||||||
commentItem.addChildren((List<RecyclerViewItem>) commentData);
|
commentItem.addChildren((List<RecyclerViewItem>) commentData);
|
||||||
((CommentViewHolder) holder).loadMoreCommentsProgressBar
|
((CommentViewHolder) holder).loadMoreCommentsProgressBar
|
||||||
.setVisibility(View.GONE);
|
.setVisibility(View.GONE);
|
||||||
@ -127,7 +129,7 @@ class CommentMultiLevelRecyclerViewAdapter extends MultiLevelAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onParseCommentFail() {
|
public void onParseCommentFailed() {
|
||||||
((CommentViewHolder) holder).loadMoreCommentsProgressBar
|
((CommentViewHolder) holder).loadMoreCommentsProgressBar
|
||||||
.setVisibility(View.GONE);
|
.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package ml.docilealligator.infinityforreddit;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.LiveData;
|
||||||
|
import android.arch.lifecycle.Transformations;
|
||||||
|
import android.arch.lifecycle.ViewModel;
|
||||||
|
import android.arch.lifecycle.ViewModelProvider;
|
||||||
|
import android.arch.paging.LivePagedListBuilder;
|
||||||
|
import android.arch.paging.PagedList;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
|
||||||
|
public class CommentViewModel extends ViewModel {
|
||||||
|
private CommentDataSourceFactory commentDataSourceFactory;
|
||||||
|
private LiveData<NetworkState> paginationNetworkState;
|
||||||
|
private LiveData<NetworkState> initialLoadingState;
|
||||||
|
private LiveData<PagedList<CommentData>> comments;
|
||||||
|
|
||||||
|
public CommentViewModel(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
|
||||||
|
String article, String comment, boolean isPost,
|
||||||
|
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
|
||||||
|
commentDataSourceFactory = new CommentDataSourceFactory(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
|
||||||
|
|
||||||
|
initialLoadingState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceMutableLiveData(),
|
||||||
|
dataSource -> dataSource.getInitialLoadStateLiveData());
|
||||||
|
paginationNetworkState = Transformations.switchMap(commentDataSourceFactory.getCommentDataSourceMutableLiveData(),
|
||||||
|
dataSource -> dataSource.getPaginationNetworkStateLiveData());
|
||||||
|
PagedList.Config pagedListConfig =
|
||||||
|
(new PagedList.Config.Builder())
|
||||||
|
.setEnablePlaceholders(false)
|
||||||
|
.setPageSize(25)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
comments = (new LivePagedListBuilder(commentDataSourceFactory, pagedListConfig)).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveData<PagedList<CommentData>> getComments() {
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveData<NetworkState> getPaginationNetworkState() {
|
||||||
|
return paginationNetworkState;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiveData<NetworkState> getInitialLoadingState() {
|
||||||
|
return initialLoadingState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refresh() {
|
||||||
|
commentDataSourceFactory.getCommentDataSource().invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void retry() {
|
||||||
|
commentDataSourceFactory.getCommentDataSource().retry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void retryLoadingMore() {
|
||||||
|
commentDataSourceFactory.getCommentDataSource().retryLoadingMore();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory extends ViewModelProvider.NewInstanceFactory {
|
||||||
|
private Retrofit retrofit;
|
||||||
|
private Locale locale;
|
||||||
|
private String subredditNamePrefixed;
|
||||||
|
private String article;
|
||||||
|
private String comment;
|
||||||
|
private boolean isPost;
|
||||||
|
private CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback;
|
||||||
|
|
||||||
|
public Factory(Retrofit retrofit, Locale locale, String subredditNamePrefixed,
|
||||||
|
String article, String comment, boolean isPost,
|
||||||
|
CommentDataSource.OnCommentFetchedCallback onCommentFetchedCallback) {
|
||||||
|
this.retrofit = retrofit;
|
||||||
|
this.locale = locale;
|
||||||
|
this.subredditNamePrefixed = subredditNamePrefixed;
|
||||||
|
this.article = article;
|
||||||
|
this.comment = comment;
|
||||||
|
this.isPost = isPost;
|
||||||
|
this.onCommentFetchedCallback = onCommentFetchedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||||
|
return (T) new CommentViewModel(retrofit, locale, subredditNamePrefixed, article, comment, isPost, onCommentFetchedCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -68,4 +68,7 @@ public class JSONUtils {
|
|||||||
public static final String IS_GOLD_KEY = "is_gold";
|
public static final String IS_GOLD_KEY = "is_gold";
|
||||||
public static final String IS_FRIEND_KEY = "is_friend";
|
public static final String IS_FRIEND_KEY = "is_friend";
|
||||||
static final String KIND_KEY = "kind";
|
static final String KIND_KEY = "kind";
|
||||||
|
static final String JSON_KEY = "json";
|
||||||
|
static final String THINGS_KEY = "things";
|
||||||
|
static final String PARENT_ID_KEY = "parent_id";
|
||||||
}
|
}
|
||||||
|
@ -15,73 +15,118 @@ import java.util.Locale;
|
|||||||
|
|
||||||
class ParseComment {
|
class ParseComment {
|
||||||
interface ParseCommentListener {
|
interface ParseCommentListener {
|
||||||
void onParseCommentSuccess(List<?> commentData, int moreCommentCount);
|
void onParseCommentSuccess(List<?> commentData, String parentId, String commaSeparatedChildren);
|
||||||
void onParseCommentFail();
|
void onParseCommentFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParseMoreCommentBasicInfoListener {
|
||||||
|
void onParseMoreCommentBasicInfoSuccess(String commaSeparatedChildrenId);
|
||||||
|
void onParseMoreCommentBasicInfoFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseComment(String response, ArrayList<CommentData> commentData, Locale locale,
|
static void parseComment(String response, ArrayList<CommentData> commentData, Locale locale,
|
||||||
boolean isPost, int parentDepth, ParseCommentListener parseCommentListener) {
|
boolean isPost, int parentDepth, int childrenStartIndex, ParseCommentListener parseCommentListener) {
|
||||||
new ParseCommentAsyncTask(response, commentData, locale, isPost, parentDepth, parseCommentListener).execute();
|
try {
|
||||||
|
JSONArray childrenArray = new JSONArray(response);
|
||||||
|
|
||||||
|
if(isPost) {
|
||||||
|
childrenArray = childrenArray.getJSONObject(childrenStartIndex).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
|
} else {
|
||||||
|
childrenArray = childrenArray.getJSONObject(childrenStartIndex).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY)
|
||||||
|
.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONObject(JSONUtils.REPLIES_KEY)
|
||||||
|
.getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
|
}
|
||||||
|
new ParseCommentAsyncTask(childrenArray, commentData, locale, isPost, parentDepth, childrenStartIndex, parseCommentListener).execute();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.i("comment json error", e.getMessage());
|
||||||
|
parseCommentListener.onParseCommentFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseMoreCommentBasicInfo(String response, ParseMoreCommentBasicInfoListener parseMoreCommentBasicInfoListener) {
|
||||||
|
new ParseMoreCommentBasicInfoAsyncTask(response, parseMoreCommentBasicInfoListener).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parseMoreComment(String response, ArrayList<CommentData> commentData, Locale locale,
|
||||||
|
boolean isPost, int parentDepth, int childrenStartIndex, ParseCommentListener parseCommentListener) {
|
||||||
|
try {
|
||||||
|
JSONArray childrenArray = new JSONObject(response).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
|
new ParseCommentAsyncTask(childrenArray, commentData, locale, isPost, parentDepth, childrenStartIndex, parseCommentListener).execute();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.i("comment json error", e.getMessage());
|
||||||
|
parseCommentListener.onParseCommentFailed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ParseCommentAsyncTask extends AsyncTask<Void, Void, Void> {
|
private static class ParseCommentAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||||
private JSONArray jsonResponse;
|
private JSONArray comments;
|
||||||
private ArrayList<CommentData> commentData;
|
private ArrayList<CommentData> commentData;
|
||||||
private ArrayList<CommentData> newcommentData;
|
private ArrayList<CommentData> newcommentData;
|
||||||
|
private StringBuilder commaSeparatedChildren;
|
||||||
private Locale locale;
|
private Locale locale;
|
||||||
private boolean isPost;
|
private boolean isPost;
|
||||||
private int parentDepth;
|
private int parentDepth;
|
||||||
|
private int childrenStartIndex;
|
||||||
private ParseCommentListener parseCommentListener;
|
private ParseCommentListener parseCommentListener;
|
||||||
private boolean parseFailed;
|
private boolean parseFailed;
|
||||||
private int moreCommentCount;
|
private String parentId;
|
||||||
|
|
||||||
ParseCommentAsyncTask(String response, ArrayList<CommentData> commentData, Locale locale,
|
ParseCommentAsyncTask(JSONArray comments, ArrayList<CommentData> commentData, Locale locale,
|
||||||
boolean isPost, int parentDepth, ParseCommentListener parseCommentListener){
|
boolean isPost, int parentDepth, int childrenStartIndex, ParseCommentListener parseCommentListener){
|
||||||
try {
|
this.comments = comments;
|
||||||
jsonResponse = new JSONArray(response);
|
this.commentData = commentData;
|
||||||
this.commentData = commentData;
|
newcommentData = new ArrayList<>();
|
||||||
newcommentData = new ArrayList<>();
|
commaSeparatedChildren = new StringBuilder();
|
||||||
this.locale = locale;
|
this.locale = locale;
|
||||||
this.isPost = isPost;
|
this.isPost = isPost;
|
||||||
this.parentDepth = parentDepth;
|
this.parentDepth = parentDepth;
|
||||||
this.parseCommentListener = parseCommentListener;
|
this.childrenStartIndex = childrenStartIndex;
|
||||||
parseFailed = false;
|
parseFailed = false;
|
||||||
} catch (JSONException e) {
|
this.parseCommentListener = parseCommentListener;
|
||||||
Log.i("comment json error", e.getMessage());
|
|
||||||
parseCommentListener.onParseCommentFail();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... voids) {
|
protected Void doInBackground(Void... voids) {
|
||||||
try {
|
try {
|
||||||
moreCommentCount = 0;
|
|
||||||
int actualCommentLength;
|
int actualCommentLength;
|
||||||
JSONArray allComments;
|
ArrayList<String> children = new ArrayList<>();
|
||||||
|
|
||||||
if(isPost) {
|
/*if(isPost) {
|
||||||
allComments = jsonResponse.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
allComments = comments.getJSONObject(childrenStartIndex).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
} else {
|
} else {
|
||||||
allComments = jsonResponse.getJSONObject(1).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY)
|
allComments = comments.getJSONObject(childrenStartIndex).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY)
|
||||||
.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONObject(JSONUtils.REPLIES_KEY)
|
.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONObject(JSONUtils.REPLIES_KEY)
|
||||||
.getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
.getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
}
|
}*/
|
||||||
if(allComments.length() == 0) {
|
if(comments.length() == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject more = allComments.getJSONObject(allComments.length() - 1).getJSONObject(JSONUtils.DATA_KEY);
|
JSONObject more = comments.getJSONObject(comments.length() - 1).getJSONObject(JSONUtils.DATA_KEY);
|
||||||
|
|
||||||
//Maybe children contain only comments and no more info
|
//Maybe children contain only comments and no more info
|
||||||
if(more.has(JSONUtils.COUNT_KEY)) {
|
if(more.has(JSONUtils.COUNT_KEY)) {
|
||||||
moreCommentCount = more.getInt(JSONUtils.COUNT_KEY);
|
JSONArray childrenArray = more.getJSONArray(JSONUtils.CHILDREN_KEY);
|
||||||
actualCommentLength = allComments.length() - 1;
|
|
||||||
|
parentId = more.getString(JSONUtils.PARENT_ID_KEY);
|
||||||
|
for(int i = 0; i < childrenArray.length(); i++) {
|
||||||
|
children.add(childrenArray.getString(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(String c : children) {
|
||||||
|
commaSeparatedChildren.append(c).append(",");
|
||||||
|
}
|
||||||
|
commaSeparatedChildren.deleteCharAt(commaSeparatedChildren.length() - 1);
|
||||||
|
|
||||||
|
actualCommentLength = comments.length() - 1;
|
||||||
} else {
|
} else {
|
||||||
actualCommentLength = allComments.length();
|
actualCommentLength = comments.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < actualCommentLength; i++) {
|
for (int i = 0; i < actualCommentLength; i++) {
|
||||||
JSONObject data = allComments.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
|
JSONObject data = comments.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY);
|
||||||
String id = data.getString(JSONUtils.ID_KEY);
|
String id = data.getString(JSONUtils.ID_KEY);
|
||||||
String fullName = data.getString(JSONUtils.LINK_ID_KEY);
|
String fullName = data.getString(JSONUtils.LINK_ID_KEY);
|
||||||
String author = data.getString(JSONUtils.AUTHOR_KEY);
|
String author = data.getString(JSONUtils.AUTHOR_KEY);
|
||||||
@ -100,7 +145,12 @@ class ParseComment {
|
|||||||
String formattedSubmitTime = new SimpleDateFormat("MMM d, YYYY, HH:mm",
|
String formattedSubmitTime = new SimpleDateFormat("MMM d, YYYY, HH:mm",
|
||||||
locale).format(submitTimeCalendar.getTime());
|
locale).format(submitTimeCalendar.getTime());
|
||||||
|
|
||||||
int depth = data.getInt(JSONUtils.DEPTH_KEY) + parentDepth;
|
int depth;
|
||||||
|
if(data.has(JSONUtils.DEPTH_KEY)) {
|
||||||
|
depth = data.getInt(JSONUtils.DEPTH_KEY) + parentDepth;
|
||||||
|
} else {
|
||||||
|
depth = parentDepth;
|
||||||
|
}
|
||||||
boolean collapsed = data.getBoolean(JSONUtils.COLLAPSED_KEY);
|
boolean collapsed = data.getBoolean(JSONUtils.COLLAPSED_KEY);
|
||||||
boolean hasReply = !(data.get(JSONUtils.REPLIES_KEY) instanceof String);
|
boolean hasReply = !(data.get(JSONUtils.REPLIES_KEY) instanceof String);
|
||||||
|
|
||||||
@ -117,9 +167,55 @@ class ParseComment {
|
|||||||
protected void onPostExecute(Void aVoid) {
|
protected void onPostExecute(Void aVoid) {
|
||||||
if(!parseFailed) {
|
if(!parseFailed) {
|
||||||
commentData.addAll(newcommentData);
|
commentData.addAll(newcommentData);
|
||||||
parseCommentListener.onParseCommentSuccess(commentData, moreCommentCount);
|
parseCommentListener.onParseCommentSuccess(commentData, parentId, commaSeparatedChildren.toString());
|
||||||
} else {
|
} else {
|
||||||
parseCommentListener.onParseCommentFail();
|
parseCommentListener.onParseCommentFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ParseMoreCommentBasicInfoAsyncTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
private JSONArray children;
|
||||||
|
private StringBuilder commaSeparatedChildren;
|
||||||
|
private ParseMoreCommentBasicInfoListener parseMoreCommentBasicInfoListener;
|
||||||
|
private boolean parseFailed;
|
||||||
|
|
||||||
|
ParseMoreCommentBasicInfoAsyncTask(String response, ParseMoreCommentBasicInfoListener parseMoreCommentBasicInfoListener) {
|
||||||
|
this.parseMoreCommentBasicInfoListener = parseMoreCommentBasicInfoListener;
|
||||||
|
try {
|
||||||
|
children = new JSONObject(response).getJSONObject(JSONUtils.JSON_KEY)
|
||||||
|
.getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.THINGS_KEY);
|
||||||
|
commaSeparatedChildren = new StringBuilder();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
parseMoreCommentBasicInfoListener.onParseMoreCommentBasicInfoFailed();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... voids) {
|
||||||
|
try {
|
||||||
|
for(int i = 0; i < children.length(); i++) {
|
||||||
|
commaSeparatedChildren.append(children.getJSONObject(i).getJSONObject(JSONUtils.DATA_KEY).getString(JSONUtils.ID_KEY));
|
||||||
|
commaSeparatedChildren.append(",");
|
||||||
|
}
|
||||||
|
commaSeparatedChildren.deleteCharAt(commaSeparatedChildren.length() - 1);
|
||||||
|
parseFailed = false;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
parseMoreCommentBasicInfoListener.onParseMoreCommentBasicInfoFailed();
|
||||||
|
parseFailed = true;
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Void aVoid) {
|
||||||
|
super.onPostExecute(aVoid);
|
||||||
|
if(!parseFailed) {
|
||||||
|
parseMoreCommentBasicInfoListener.onParseMoreCommentBasicInfoSuccess(commaSeparatedChildren.toString());
|
||||||
|
} else {
|
||||||
|
parseMoreCommentBasicInfoListener.onParseMoreCommentBasicInfoFailed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ class PostDataSource extends PageKeyedDataSource<String, Post> {
|
|||||||
Call<String> bestPost = api.getBestPosts(null, RedditUtils.getOAuthHeader(accessToken));
|
Call<String> bestPost = api.getBestPosts(null, RedditUtils.getOAuthHeader(accessToken));
|
||||||
bestPost.enqueue(new Callback<String>() {
|
bestPost.enqueue(new Callback<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<String> call, retrofit2.Response<String> response) {
|
public void onResponse(@NonNull Call<String> call, @NonNull retrofit2.Response<String> response) {
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
ParsePost.parsePost(response.body(), locale,
|
ParsePost.parsePost(response.body(), locale,
|
||||||
new ParsePost.ParsePostListener() {
|
new ParsePost.ParsePostListener() {
|
||||||
|
@ -53,9 +53,15 @@ public interface RedditAPI {
|
|||||||
@POST("api/subscribe")
|
@POST("api/subscribe")
|
||||||
Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);
|
Call<String> subredditSubscription(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> params);
|
||||||
|
|
||||||
@PUT("/api/v1/me/friends/username")
|
@PUT("api/v1/me/friends/username")
|
||||||
Call<String> subscribeUser(@HeaderMap Map<String, String> headers);
|
Call<String> subscribeUser(@HeaderMap Map<String, String> headers);
|
||||||
|
|
||||||
@DELETE("/api/v1/me/friends/username")
|
@DELETE("api/v1/me/friends/username")
|
||||||
Call<String> unsubscribeUser(@HeaderMap Map<String, String> headers);
|
Call<String> unsubscribeUser(@HeaderMap Map<String, String> headers);
|
||||||
|
|
||||||
|
@GET("api/morechildren?api_type=json&raw_json=1")
|
||||||
|
Call<String> getMoreChildren(@Query("link_id") String linkId, @Query("children") String children);
|
||||||
|
|
||||||
|
@GET("{subredditNamePrefixed}/api/info.json?raw_json=1")
|
||||||
|
Call<String> getInfo(@Path("subredditNamePrefixed") String subredditNamePrefixed, @Query("id") String id);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import java.util.Map;
|
|||||||
public class RedditUtils {
|
public class RedditUtils {
|
||||||
static final String OAUTH_URL ="https://www.reddit.com/api/v1/authorize.compact";
|
static final String OAUTH_URL ="https://www.reddit.com/api/v1/authorize.compact";
|
||||||
static final String OAUTH_API_BASE_URI = "https://oauth.reddit.com";
|
static final String OAUTH_API_BASE_URI = "https://oauth.reddit.com";
|
||||||
static final String API_BASE_URI = "https://api.reddit.com";
|
static final String API_BASE_URI = "https://www.reddit.com";
|
||||||
|
|
||||||
static final String CLIENT_ID_KEY = "client_id";
|
static final String CLIENT_ID_KEY = "client_id";
|
||||||
static final String CLIENT_ID = "";
|
static final String CLIENT_ID = "";
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ml.docilealligator.infinityforreddit;
|
package ml.docilealligator.infinityforreddit;
|
||||||
|
|
||||||
|
import android.arch.lifecycle.ViewModelProviders;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
||||||
@ -18,6 +19,7 @@ import android.support.v7.app.AppCompatActivity;
|
|||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
import android.support.v7.widget.DividerItemDecoration;
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
@ -36,12 +38,8 @@ import com.bumptech.glide.request.RequestListener;
|
|||||||
import com.bumptech.glide.request.RequestOptions;
|
import com.bumptech.glide.request.RequestOptions;
|
||||||
import com.bumptech.glide.request.target.Target;
|
import com.bumptech.glide.request.target.Target;
|
||||||
import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
|
import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
|
||||||
import com.multilevelview.MultiLevelRecyclerView;
|
|
||||||
import com.santalu.aspectratioimageview.AspectRatioImageView;
|
import com.santalu.aspectratioimageview.AspectRatioImageView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
@ -65,7 +63,6 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
private int orientation;
|
private int orientation;
|
||||||
private String orientationState = "OS";
|
private String orientationState = "OS";
|
||||||
|
|
||||||
private int mMoreCommentCount;
|
|
||||||
private Post mPost;
|
private Post mPost;
|
||||||
|
|
||||||
@BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout;
|
@BindView(R.id.coordinator_layout_view_post_detail) CoordinatorLayout mCoordinatorLayout;
|
||||||
@ -94,7 +91,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@BindView(R.id.comment_progress_bar_view_post_detail) CircleProgressBar mCommentProgressbar;
|
@BindView(R.id.comment_progress_bar_view_post_detail) CircleProgressBar mCommentProgressbar;
|
||||||
@BindView(R.id.comment_card_view_view_post_detail) CardView mCommentCardView;
|
@BindView(R.id.comment_card_view_view_post_detail) CardView mCommentCardView;
|
||||||
@BindView(R.id.recycler_view_view_post_detail) MultiLevelRecyclerView mRecyclerView;
|
@BindView(R.id.recycler_view_view_post_detail) RecyclerView mRecyclerView;
|
||||||
|
|
||||||
@BindView(R.id.no_comment_wrapper_linear_layout_view_post_detail) LinearLayout mNoCommentWrapperLinearLayout;
|
@BindView(R.id.no_comment_wrapper_linear_layout_view_post_detail) LinearLayout mNoCommentWrapperLinearLayout;
|
||||||
@BindView(R.id.no_comment_image_view_view_post_detail) ImageView mNoCommentImageView;
|
@BindView(R.id.no_comment_image_view_view_post_detail) ImageView mNoCommentImageView;
|
||||||
@ -330,7 +327,32 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
queryComment();
|
//queryComment();
|
||||||
|
|
||||||
|
CommentAdapter adapter = new CommentAdapter(this, mRetrofit, mOauthRetrofit, mSharedPreferences,
|
||||||
|
mRecyclerView, mPost.getSubredditNamePrefixed(), mPost.getId(), getResources().getConfiguration().locale);
|
||||||
|
|
||||||
|
CommentViewModel.Factory factory = new CommentViewModel.Factory(mRetrofit, getResources().getConfiguration().locale,
|
||||||
|
mPost.getSubredditNamePrefixed(), mPost.getId(), null, true, new CommentDataSource.OnCommentFetchedCallback() {
|
||||||
|
@Override
|
||||||
|
public void hasComment() {
|
||||||
|
mCommentProgressbar.setVisibility(View.GONE);
|
||||||
|
/*mRecyclerView.removeItemClickListeners();
|
||||||
|
mRecyclerView.setToggleItemOnClick(false);
|
||||||
|
mRecyclerView.setAccordion(false);*/
|
||||||
|
mRecyclerView.setAdapter(adapter);
|
||||||
|
mCommentCardView.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void noComment() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
CommentViewModel commentViewModel = ViewModelProviders.of(this, factory).get(CommentViewModel.class);
|
||||||
|
commentViewModel.getComments().observe(this, posts -> adapter.submitList(posts));
|
||||||
|
|
||||||
|
|
||||||
mUpvoteButton.setOnClickListener(view -> {
|
mUpvoteButton.setOnClickListener(view -> {
|
||||||
final boolean isDownvotedBefore = mDownvoteButton.getColorFilter() != null;
|
final boolean isDownvotedBefore = mDownvoteButton.getColorFilter() != null;
|
||||||
@ -445,7 +467,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void queryComment() {
|
/*private void queryComment() {
|
||||||
mCommentProgressbar.setVisibility(View.VISIBLE);
|
mCommentProgressbar.setVisibility(View.VISIBLE);
|
||||||
mNoCommentWrapperLinearLayout.setVisibility(View.GONE);
|
mNoCommentWrapperLinearLayout.setVisibility(View.GONE);
|
||||||
FetchComment.fetchComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getId(),
|
FetchComment.fetchComment(mRetrofit, mPost.getSubredditNamePrefixed(), mPost.getId(),
|
||||||
@ -453,12 +475,12 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onFetchCommentSuccess(String response) {
|
public void onFetchCommentSuccess(String response) {
|
||||||
ParseComment.parseComment(response, new ArrayList<CommentData>(),
|
ParseComment.parseComment(response, new ArrayList<CommentData>(),
|
||||||
getResources().getConfiguration().locale, true, 0,
|
getResources().getConfiguration().locale, true, 0, 1,
|
||||||
new ParseComment.ParseCommentListener() {
|
new ParseComment.ParseCommentListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onParseCommentSuccess(List<?> commentData, int moreCommentCount) {
|
public void onParseCommentSuccess(List<?> commentData,
|
||||||
|
String parentId, String commaSeparatedChildren) {
|
||||||
mCommentProgressbar.setVisibility(View.GONE);
|
mCommentProgressbar.setVisibility(View.GONE);
|
||||||
mMoreCommentCount = moreCommentCount;
|
|
||||||
if (commentData.size() > 0) {
|
if (commentData.size() > 0) {
|
||||||
CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter(
|
CommentMultiLevelRecyclerViewAdapter adapter = new CommentMultiLevelRecyclerViewAdapter(
|
||||||
ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit,
|
ViewPostDetailActivity.this, mRetrofit, mOauthRetrofit,
|
||||||
@ -477,7 +499,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onParseCommentFail() {
|
public void onParseCommentFailed() {
|
||||||
mCommentProgressbar.setVisibility(View.GONE);
|
mCommentProgressbar.setVisibility(View.GONE);
|
||||||
showRetrySnackbar();
|
showRetrySnackbar();
|
||||||
}
|
}
|
||||||
@ -490,7 +512,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
showRetrySnackbar();
|
showRetrySnackbar();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private void loadImage() {
|
private void loadImage() {
|
||||||
RequestBuilder imageRequestBuilder = glide.load(mPost.getPreviewUrl())
|
RequestBuilder imageRequestBuilder = glide.load(mPost.getPreviewUrl())
|
||||||
@ -549,7 +571,7 @@ public class ViewPostDetailActivity extends AppCompatActivity {
|
|||||||
snackbar.setAction(R.string.retry, new View.OnClickListener() {
|
snackbar.setAction(R.string.retry, new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
queryComment();
|
//queryComment();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
snackbar.show();
|
snackbar.show();
|
||||||
|
@ -293,7 +293,7 @@
|
|||||||
android:textColor="#000000"
|
android:textColor="#000000"
|
||||||
android:textSize="18sp" />
|
android:textSize="18sp" />
|
||||||
|
|
||||||
<com.multilevelview.MultiLevelRecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/recycler_view_view_post_detail"
|
android:id="@+id/recycler_view_view_post_detail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
@ -7,7 +7,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
classpath 'com.android.tools.build:gradle:3.3.1'
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
Loading…
x
Reference in New Issue
Block a user