From 23bf92d9cf32f1d62aaad1157f329f9f8943f6c7 Mon Sep 17 00:00:00 2001 From: Alex Ning Date: Sun, 19 Aug 2018 00:03:56 +0800 Subject: Added feature: Vote in ViewPostDetailActivity. Fix some behavior after the vote fails. --- .idea/caches/build_file_checksums.ser | Bin 533 -> 533 bytes app/build.gradle | 12 +- .../BestPostRecyclerViewAdapter.java | 8 +- .../infinityforreddit/MainActivity.java | 2 +- .../infinityforreddit/ViewPostDetailActivity.java | 180 ++++++++++++++++++++- .../infinityforreddit/VoteThing.java | 69 +++++++- 6 files changed, 250 insertions(+), 21 deletions(-) diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 034a690d..e7930936 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index 95becfb6..26b73a0a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,10 +28,10 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:appcompat-v7:28.0.0-beta01' - implementation 'com.android.support:design:28.0.0-beta01' + implementation 'com.android.support:appcompat-v7:28.0.0-rc01' + implementation 'com.android.support:design:28.0.0-rc01' implementation 'com.android.support.constraint:constraint-layout:1.1.2' - implementation 'com.android.support:support-v4:28.0.0-beta01' + implementation 'com.android.support:support-v4:28.0.0-rc01' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' @@ -39,9 +39,9 @@ dependencies { implementation 'de.hdodenhof:circleimageview:2.2.0' implementation 'com.google.android.exoplayer:exoplayer:2.7.0' implementation 'com.google.android.exoplayer:exoplayer-dash:2.7.0' - implementation 'com.android.support:customtabs:28.0.0-beta01' + implementation 'com.android.support:customtabs:28.0.0-rc01' implementation 'com.alexvasilkov:gesture-views:2.5.2' - implementation 'com.android.support:cardview-v7:28.0.0-beta01' + implementation 'com.android.support:cardview-v7:28.0.0-rc01' implementation 'com.github.bumptech.glide:glide:4.6.1' implementation 'com.github.pwittchen:swipe-rx2:0.3.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1' @@ -52,4 +52,6 @@ dependencies { // Lifecycle components implementation "android.arch.lifecycle:extensions:$rootProject.archLifecycleVersion" annotationProcessor "android.arch.lifecycle:compiler:$rootProject.archLifecycleVersion" + implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' + implementation 'io.reactivex.rxjava2:rxjava:2.2.0' } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/BestPostRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/BestPostRecyclerViewAdapter.java index 5978b407..d5d8614f 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/BestPostRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/BestPostRecyclerViewAdapter.java @@ -2,6 +2,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Context; import android.content.Intent; +import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; import android.support.annotation.NonNull; @@ -299,6 +300,8 @@ class BestPostRecyclerViewAdapter extends RecyclerView.Adapter(), new ArrayList(), new ArrayList()) .fetchSubscribedSubreddits(new FetchSubscribedThing.FetchSubscribedSubredditsListener() { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java index 47a0ef7f..050db26c 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/ViewPostDetailActivity.java @@ -1,6 +1,7 @@ package ml.docilealligator.infinityforreddit; import android.content.Intent; +import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -8,6 +9,7 @@ import android.support.annotation.Nullable; import android.support.customtabs.CustomTabsIntent; import android.support.design.widget.CoordinatorLayout; import android.support.design.widget.Snackbar; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.CardView; import android.support.v7.widget.DividerItemDecoration; @@ -20,6 +22,7 @@ import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; +import android.widget.Toast; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; @@ -52,7 +55,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { private LinearLayout mNoCommentWrapperLinearLayout; private ImageView mNoCommentImageView; - private RequestQueue mVoteThingQueue; + private RequestQueue mVoteThingRequestQueue; private RequestQueue mAcquireAccessTokenRequestQueue; private RequestQueue mCommentQueue; @@ -82,9 +85,9 @@ public class ViewPostDetailActivity extends AppCompatActivity { ImageView imageView = findViewById(R.id.image_view_view_post_detail); ImageView noPreviewLinkImageView = findViewById(R.id.image_view_no_preview_link_view_post_detail); - ImageView plusButton = findViewById(R.id.plus_button_view_post_detail); - TextView scoreTextView = findViewById(R.id.score_text_view_view_post_detail); - ImageView minusButton = findViewById(R.id.minus_button_view_post_detail); + final ImageView upvoteButton = findViewById(R.id.plus_button_view_post_detail); + final TextView scoreTextView = findViewById(R.id.score_text_view_view_post_detail); + final ImageView downvoteButton = findViewById(R.id.minus_button_view_post_detail); ImageView shareButton = findViewById(R.id.share_button_view_post_detail); mCommentProgressbar = findViewById(R.id.comment_progress_bar_view_post_detail); @@ -104,10 +107,21 @@ public class ViewPostDetailActivity extends AppCompatActivity { Glide.with(this).load(R.drawable.subreddit_default_icon).into(subredditIconCircleImageView); } + switch (mPostData.getVoteType()) { + case 1: + //Upvote + upvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + break; + case -1: + //Downvote + downvoteButton.setColorFilter(ContextCompat.getColor(this, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + break; + } + mRecyclerView.setNestedScrollingEnabled(false); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); - mVoteThingQueue = Volley.newRequestQueue(this); + mVoteThingRequestQueue = Volley.newRequestQueue(this); mAcquireAccessTokenRequestQueue = Volley.newRequestQueue(this); mCommentQueue = Volley.newRequestQueue(this); @@ -284,6 +298,160 @@ public class ViewPostDetailActivity extends AppCompatActivity { } } queryComment(); + + /*final Observable observable = Observable.create( + new ObservableOnSubscribe() { + @Override + public void subscribe(ObservableEmitter emitter) throws Exception { + emitter.onNext(mPostData.getVoteType()); + emitter.onComplete(); + Log.i("asdasdf", "adasdfasdf"); + Toast.makeText(ViewPostDetailActivity.this, "observable", Toast.LENGTH_SHORT).show(); + } + } + ); + + final Observer observer = new Observer() { + @Override + public void onSubscribe(Disposable d) { + + } + + @Override + public void onNext(Object o) { + + } + + @Override + public void onError(Throwable e) { + + } + + @Override + public void onComplete() { + Toast.makeText(ViewPostDetailActivity.this, "complete", Toast.LENGTH_SHORT).show(); + } + };*/ + + upvoteButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + //observable.subscribe(observer); + final boolean isDownvotedBefore = downvoteButton.getColorFilter() != null; + + final ColorFilter downVoteButtonColorFilter = downvoteButton.getColorFilter(); + downvoteButton.clearColorFilter(); + + if (upvoteButton.getColorFilter() == null) { + upvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + if(isDownvotedBefore) { + scoreTextView.setText(Integer.toString(mPostData.getScore() + 2)); + } else { + scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); + } + + new VoteThing(ViewPostDetailActivity.this, mVoteThingRequestQueue, mAcquireAccessTokenRequestQueue).votePost(new VoteThing.VoteThingWithoutPositionListener() { + @Override + public void onVoteThingSuccess() { + mPostData.setVoteType(1); + if(isDownvotedBefore) { + mPostData.setScore(mPostData.getScore() + 2); + } else { + mPostData.setScore(mPostData.getScore() + 1); + } + } + + @Override + public void onVoteThingFail() { + Toast.makeText(ViewPostDetailActivity.this, "Cannot upvote this post", Toast.LENGTH_SHORT).show(); + upvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mPostData.getScore())); + downvoteButton.setColorFilter(downVoteButtonColorFilter); + } + }, mPostData.getFullName(), RedditUtils.DIR_UPVOTE, 1); + } else { + //Upvoted before + upvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); + + new VoteThing(ViewPostDetailActivity.this, mVoteThingRequestQueue, mAcquireAccessTokenRequestQueue).votePost(new VoteThing.VoteThingWithoutPositionListener() { + @Override + public void onVoteThingSuccess() { + mPostData.setVoteType(0); + mPostData.setScore(mPostData.getScore() - 1); + } + + @Override + public void onVoteThingFail() { + Toast.makeText(ViewPostDetailActivity.this, "Cannot unvote this post", Toast.LENGTH_SHORT).show(); + scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); + upvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.colorPrimary), android.graphics.PorterDuff.Mode.SRC_IN); + mPostData.setScore(mPostData.getScore() + 1); + } + }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); + } + } + }); + + downvoteButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + //observable.subscribe(observer); + final boolean isUpvotedBefore = upvoteButton.getColorFilter() != null; + + final ColorFilter upvoteButtonColorFilter = upvoteButton.getColorFilter(); + upvoteButton.clearColorFilter(); + + if (downvoteButton.getColorFilter() == null) { + downvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + if (isUpvotedBefore) { + scoreTextView.setText(Integer.toString(mPostData.getScore() - 2)); + } else { + scoreTextView.setText(Integer.toString(mPostData.getScore() - 1)); + } + + new VoteThing(ViewPostDetailActivity.this, mVoteThingRequestQueue, mAcquireAccessTokenRequestQueue).votePost(new VoteThing.VoteThingWithoutPositionListener() { + @Override + public void onVoteThingSuccess() { + mPostData.setVoteType(-1); + if(isUpvotedBefore) { + mPostData.setScore(mPostData.getScore() - 2); + } else { + mPostData.setScore(mPostData.getScore() - 1); + } + } + + @Override + public void onVoteThingFail() { + Toast.makeText(ViewPostDetailActivity.this, "Cannot downvote this post", Toast.LENGTH_SHORT).show(); + downvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mPostData.getScore())); + upvoteButton.setColorFilter(upvoteButtonColorFilter); + } + }, mPostData.getFullName(), RedditUtils.DIR_DOWNVOTE, 1); + } else { + //Down voted before + downvoteButton.clearColorFilter(); + scoreTextView.setText(Integer.toString(mPostData.getScore() + 1)); + + new VoteThing(ViewPostDetailActivity.this, mVoteThingRequestQueue, mAcquireAccessTokenRequestQueue).votePost(new VoteThing.VoteThingWithoutPositionListener() { + @Override + public void onVoteThingSuccess() { + mPostData.setVoteType(0); + mPostData.setScore(mPostData.getScore()); + } + + @Override + public void onVoteThingFail() { + Toast.makeText(ViewPostDetailActivity.this, "Cannot unvote this post", Toast.LENGTH_SHORT).show(); + downvoteButton.setColorFilter(ContextCompat.getColor(ViewPostDetailActivity.this, R.color.minusButtonColor), android.graphics.PorterDuff.Mode.SRC_IN); + scoreTextView.setText(Integer.toString(mPostData.getScore())); + mPostData.setScore(mPostData.getScore()); + } + }, mPostData.getFullName(), RedditUtils.DIR_UNVOTE, 1); + } + } + }); } private void queryComment() { @@ -299,7 +467,7 @@ public class ViewPostDetailActivity extends AppCompatActivity { mMoreCommentCount = moreCommentCount; if(commentData.size() > 0) { CommentRecyclerViewAdapter adapter = new CommentRecyclerViewAdapter( - ViewPostDetailActivity.this, commentData, mVoteThingQueue, mAcquireAccessTokenRequestQueue); + ViewPostDetailActivity.this, commentData, mVoteThingRequestQueue, mAcquireAccessTokenRequestQueue); mRecyclerView.setAdapter(adapter); mCommentCardView.setVisibility(View.VISIBLE); } else { diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java b/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java index c6807134..0b6ef4e1 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/VoteThing.java @@ -23,8 +23,12 @@ class VoteThing { void onVoteThingFail(int position); } + interface VoteThingWithoutPositionListener { + void onVoteThingSuccess(); + void onVoteThingFail(); + } + private Context mContext; - private VoteThingListener mVoteThingListener; private RequestQueue mQueue; private RequestQueue mAcquireAccessTokenRequestQueue; @@ -34,17 +38,68 @@ class VoteThing { mAcquireAccessTokenRequestQueue = acquireAccessTokenRequestQueue; } - void votePost(VoteThingListener voteThingListener, final String fullName, final String point, final int position, final int refreshTime) { + void votePost(final VoteThingListener voteThingListener, final String fullName, final String point, final int position, final int refreshTime) { + if(mContext != null) { + if(refreshTime < 0) { + voteThingListener.onVoteThingFail(position); + return; + } + + StringRequest voteRequest = new StringRequest(Request.Method.POST, RedditUtils.OAUTH_API_BASE_URI + RedditUtils.VOTE_SUFFIX, new Response.Listener() { + @Override + public void onResponse(String response) { + voteThingListener.onVoteThingSuccess(position); + } + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + if (error instanceof AuthFailureError) { + //Access token expired + new AcquireAccessToken(mContext).refreshAccessToken(mAcquireAccessTokenRequestQueue, + new AcquireAccessToken.AcquireAccessTokenListener() { + @Override + public void onAcquireAccessTokenSuccess() { + votePost(voteThingListener, fullName, point, position, refreshTime - 1); + } + + @Override + public void onAcquireAccessTokenFail() {} + }); + } else { + voteThingListener.onVoteThingFail(position); + } + } + }) { + @Override + protected Map getParams() { + HashMap params = new HashMap<>(); + params.put(RedditUtils.DIR_KEY, point); + params.put(RedditUtils.ID_KEY, fullName); + params.put(RedditUtils.RANK_KEY, RedditUtils.RANK); + return params; + } + + @Override + public Map getHeaders() { + String accessToken = mContext.getSharedPreferences(SharedPreferencesUtils.AUTH_CODE_FILE_KEY, Context.MODE_PRIVATE).getString(SharedPreferencesUtils.ACCESS_TOKEN_KEY, ""); + return RedditUtils.getOAuthHeader(accessToken); + } + }; + voteRequest.setTag(VoteThing.class); + mQueue.add(voteRequest); + } + } + + void votePost(final VoteThingWithoutPositionListener voteThingWithoutPositionListener, final String fullName, final String point, final int refreshTime) { if(mContext != null) { if(refreshTime < 0) { - mVoteThingListener.onVoteThingFail(position); + voteThingWithoutPositionListener.onVoteThingFail(); return; } - mVoteThingListener = voteThingListener; StringRequest voteRequest = new StringRequest(Request.Method.POST, RedditUtils.OAUTH_API_BASE_URI + RedditUtils.VOTE_SUFFIX, new Response.Listener() { @Override public void onResponse(String response) { - mVoteThingListener.onVoteThingSuccess(position); + voteThingWithoutPositionListener.onVoteThingSuccess(); } }, new Response.ErrorListener() { @Override @@ -55,14 +110,14 @@ class VoteThing { new AcquireAccessToken.AcquireAccessTokenListener() { @Override public void onAcquireAccessTokenSuccess() { - votePost(mVoteThingListener, fullName, point, position, refreshTime - 1); + votePost(voteThingWithoutPositionListener, fullName, point, refreshTime - 1); } @Override public void onAcquireAccessTokenFail() {} }); } else { - mVoteThingListener.onVoteThingFail(position); + voteThingWithoutPositionListener.onVoteThingFail(); } } }) { -- cgit v1.2.3