Add vote comment

This commit is contained in:
seven332 committed 2016-03-28 02:04:05 +08:00
1 parent 0bc4569084
commit 0aad8ca1e8
11 files changed
+331 -15

No files matched your search

@@ -56,6 +56,7 @@ public class EhClient {
public static final int METHOD_GET_TORRENT_LIST = 12;
public static final int METHOD_GET_WHATS_HOT = 13;
public static final int METHOD_GET_PROFILE = 14;
public static final int METHOD_VOTE_COMMENT = 15;
private final ThreadPoolExecutor mRequestThreadPool;
private final OkHttpClient mOkHttpClient;
@@ -177,6 +178,8 @@ public class EhClient {
return EhEngine.getWhatsHot(this, mOkHttpClient);
case METHOD_GET_PROFILE:
return EhEngine.getProfile(this, mOkHttpClient);
case METHOD_VOTE_COMMENT:
return EhEngine.voteComment(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (Integer) params[3]);
default:
return new IllegalStateException("Can't detect method " + mMethod);
}
@@ -41,6 +41,7 @@ import com.hippo.ehviewer.client.parser.ProfileParser;
import com.hippo.ehviewer.client.parser.RateGalleryParser;
import com.hippo.ehviewer.client.parser.SignInParser;
import com.hippo.ehviewer.client.parser.TorrentParser;
import com.hippo.ehviewer.client.parser.VoteCommentParser;
import com.hippo.ehviewer.client.parser.WhatsHotParser;
import com.hippo.network.StatusCodeException;
import com.hippo.util.ReadableTime;
@@ -672,4 +673,40 @@ public class EhEngine {
throw e;
}
}
public static VoteCommentParser.Result voteComment(EhClient.Task task, OkHttpClient okHttpClient,
long gid, String token, long commentId, int commentVote) throws Exception {
final JSONObject json = new JSONObject();
json.put("method", "votecomment");
json.put("apiuid", APIUID);
json.put("apikey", APIKEY);
json.put("gid", gid);
json.put("token", token);
json.put("comment_id", commentId);
json.put("comment_vote", commentVote);
final RequestBody requestBody = RequestBody.create(JSON, json.toString());
String url = EhUrl.getApiUrl();
Log.d(TAG, url);
Request request = new EhRequestBuilder(url, task.getEhConfig())
.post(requestBody)
.build();
Call call = okHttpClient.newCall(request);
// Put call
task.setCall(call);
String body = null;
Headers headers = null;
int code = -1;
try {
Response response = call.execute();
code = response.code();
headers = response.headers();
body = response.body().string();
return VoteCommentParser.parse(body, commentVote);
} catch (Exception e) {
throwException(call, code, headers, body, e);
throw e;
}
}
}
@@ -21,6 +21,11 @@ import android.os.Parcelable;
public class GalleryComment implements Parcelable {
// 0 for uploader comment. can't vote
public long id;
public int score;
public boolean voteUp;
public boolean voteDown;
public long time;
public String user;
public String comment;
@@ -32,6 +37,10 @@ public class GalleryComment implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(this.id);
dest.writeInt(this.score);
dest.writeByte(voteUp ? (byte) 1 : (byte) 0);
dest.writeByte(voteDown ? (byte) 1 : (byte) 0);
dest.writeLong(this.time);
dest.writeString(this.user);
dest.writeString(this.comment);
@@ -41,16 +50,22 @@ public class GalleryComment implements Parcelable {
}
protected GalleryComment(Parcel in) {
this.id = in.readLong();
this.score = in.readInt();
this.voteUp = in.readByte() != 0;
this.voteDown = in.readByte() != 0;
this.time = in.readLong();
this.user = in.readString();
this.comment = in.readString();
}
public static final Creator<GalleryComment> CREATOR = new Creator<GalleryComment>() {
@Override
public GalleryComment createFromParcel(Parcel source) {
return new GalleryComment(source);
}
@Override
public GalleryComment[] newArray(int size) {
return new GalleryComment[size];
}
@@ -18,6 +18,7 @@ package com.hippo.ehviewer.client.parser;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.hippo.ehviewer.client.EhUtils;
import com.hippo.ehviewer.client.data.GalleryComment;
@@ -342,11 +343,35 @@ public class GalleryDetailParser {
public static GalleryComment parseComment(Element element) {
try {
GalleryComment comment = new GalleryComment();
// Id
Element a = element.previousElementSibling();
String name = a.attr("name");
comment.id = Integer.parseInt(StringUtils.trim(name).substring(1));
// Vote up and vote down
Element c4 = JsoupUtils.getElementByClass(element, "c4");
if (null != c4) {
Elements es = c4.children();
if (2 == es.size()) {
comment.voteUp = !TextUtils.isEmpty(StringUtils.trim(es.get(0).attr("style")));
comment.voteDown = !TextUtils.isEmpty(StringUtils.trim(es.get(1).attr("style")));
}
}
// Score
Element c5 = JsoupUtils.getElementByClass(element, "c5");
if (null != c5) {
Elements es = c5.children();
if (!es.isEmpty()) {
comment.score = NumberUtils.parseIntSafely(StringUtils.trim(es.get(0).text()), 0);
}
}
// time
Element c3 = JsoupUtils.getElementByClass(element, "c3");
String temp = c3.ownText();
temp = temp.substring("Posted on ".length(), temp.length() - " by:  ".length());
comment.time = WEB_COMMENT_DATE_FORMAT.parse(temp).getTime();
// user
comment.user = c3.child(0).text();
// comment
comment.comment = JsoupUtils.getElementByClass(element, "c6").html();
return comment;
} catch (Exception e) {
@@ -0,0 +1,41 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.parser;
import org.json.JSONException;
import org.json.JSONObject;
public class VoteCommentParser {
public static class Result {
public long id;
public int score;
public int vote;
public int expectVote;
}
// {"comment_id":1253922,"comment_score":-19,"comment_vote":0}
public static Result parse(String body, int vote) throws JSONException {
Result result = new Result();
JSONObject jo = new JSONObject(body);
result.id = jo.getLong("comment_id");
result.score = jo.getInt("comment_score");
result.vote = jo.getInt("comment_vote");
result.expectVote = vote;
return result;
}
}
@@ -18,19 +18,32 @@ package com.hippo.ehviewer.ui.scene;
import android.animation.Animator;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -38,7 +51,6 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import com.hippo.reveal.ViewAnimationUtils;
import com.hippo.easyrecyclerview.EasyRecyclerView;
import com.hippo.easyrecyclerview.LinearDividerItemDecoration;
import com.hippo.ehviewer.EhApplication;
@@ -48,7 +60,9 @@ import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.client.data.GalleryComment;
import com.hippo.ehviewer.client.parser.VoteCommentParser;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.reveal.ViewAnimationUtils;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.SceneFragment;
import com.hippo.text.Html;
@@ -66,7 +80,9 @@ import com.hippo.yorozuya.ViewUtils;
public final class GalleryCommentsScene extends ToolbarScene
implements EasyRecyclerView.OnItemClickListener,
EasyRecyclerView.OnItemLongClickListener, View.OnClickListener {
View.OnClickListener {
public static final String TAG = GalleryCommentsScene.class.getSimpleName();
public static final String KEY_GID = "gid";
public static final String KEY_TOKEN = "token";
@@ -172,9 +188,13 @@ public final class GalleryCommentsScene extends ToolbarScene
mRecyclerView.setSelector(RippleSalon.generateRippleDrawable(false));
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setOnItemClickListener(this);
mRecyclerView.setOnItemLongClickListener(this);
mRecyclerView.setPadding(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
mRecyclerView.getPaddingRight(), mRecyclerView.getPaddingBottom() + paddingBottomFab);
// Cancel change animator
RecyclerView.ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
if (itemAnimator instanceof DefaultItemAnimator) {
((DefaultItemAnimator) itemAnimator).setSupportsChangeAnimations(false);
}
mSendImage.setOnClickListener(this);
mFab.setOnClickListener(this);
@@ -215,6 +235,62 @@ public final class GalleryCommentsScene extends ToolbarScene
onBackPressed();
}
private void voteComment(long id, int vote) {
Context context = getContext2();
MainActivity activity = getActivity2();
if (null == context || null == activity) {
return;
}
EhRequest request = new EhRequest()
.setMethod(EhClient.METHOD_VOTE_COMMENT)
.setArgs(mGid, mToken, id, vote)
.setCallback(new VoteCommentListener(context,
activity.getStageId(), getTag()));
EhApplication.getEhClient(context).execute(request);
}
private void showCommentDialog(final int position) {
final Context context = getContext2();
if (null == context || null == mComments || position >= mComments.length || position < 0) {
return;
}
final GalleryComment comment = mComments[position];
String[] menuArray;
Resources resources = context.getResources();
if (0 == comment.id) {
// 0 id is uploader comment, can't vote
menuArray = new String[1];
menuArray[0] = resources.getString(R.string.copy_comment_text);
} else {
menuArray = new String[3];
menuArray[0] = resources.getString(R.string.copy_comment_text);
menuArray[1] = resources.getString(comment.voteUp ? R.string.cancel_vote_up : R.string.vote_up);
menuArray[2] = resources.getString(comment.voteDown ? R.string.cancel_vote_down : R.string.vote_down);
}
new AlertDialog.Builder(context)
.setItems(menuArray, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0: // Copy
ClipboardManager cmb = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
cmb.setPrimaryClip(ClipData.newPlainText(null, comment.comment));
showTip(R.string.copied_to_clipboard, LENGTH_SHORT);
break;
case 1: // Vote up
voteComment(comment.id, 1);
break;
case 2: // Vote down
voteComment(comment.id, -1);
break;
}
}
}).show();
}
@Override
public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) {
Activity activity = getActivity2();
@@ -233,12 +309,10 @@ public final class GalleryCommentsScene extends ToolbarScene
return true;
}
}
return false;
}
@Override
public boolean onItemLongClick(EasyRecyclerView parent, View view, int position, long id) {
return false;
showCommentDialog(position);
return true;
}
private void updateView(boolean animation) {
@@ -406,9 +480,9 @@ public final class GalleryCommentsScene extends ToolbarScene
private class CommentHolder extends RecyclerView.ViewHolder {
public TextView user;
public TextView time;
public LinkifyTextView comment;
public final TextView user;
public final TextView time;
public final LinkifyTextView comment;
public CommentHolder(View itemView) {
super(itemView);
@@ -432,6 +506,24 @@ public final class GalleryCommentsScene extends ToolbarScene
return new CommentHolder(mInflater.inflate(R.layout.item_gallery_comment, parent, false));
}
public CharSequence generateComment(Context context, TextView textView, GalleryComment comment) {
SpannableStringBuilder ssb = Html.fromHtml(comment.comment, new URLImageGetter(textView,
EhApplication.getConaco(context)), null);
if (0 != comment.id && 0 != comment.score) {
int score = comment.score;
String scoreString = score > 0 ? "+" + score : Integer.toString(score);
SpannableString ss = new SpannableString(scoreString);
ss.setSpan(new RelativeSizeSpan(0.8f), 0, scoreString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(new StyleSpan(Typeface.BOLD), 0, scoreString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ss.setSpan(new ForegroundColorSpan(context.getResources().getColor(R.color.secondary_text_default_light))
, 0, scoreString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append(" ").append(ss);
}
return TextUrl.handleTextUrl(ssb);
}
@Override
public void onBindViewHolder(CommentHolder holder, int position) {
Context context = getContext2();
@@ -442,8 +534,7 @@ public final class GalleryCommentsScene extends ToolbarScene
GalleryComment comment = mComments[position];
holder.user.setText(comment.user);
holder.time.setText(ReadableTime.getTimeAgo(comment.time));
holder.comment.setText(TextUrl.handleTextUrl(Html.fromHtml(comment.comment,
new URLImageGetter(holder.comment, EhApplication.getConaco(context)), null)));
holder.comment.setText(generateComment(context, holder.comment, comment));
}
@Override
@@ -471,6 +562,37 @@ public final class GalleryCommentsScene extends ToolbarScene
updateView(true);
}
private void onVoteCommentSuccess(VoteCommentParser.Result result) {
if (null == mAdapter || null == mComments) {
return;
}
int position = -1;
for (int i = 0, n = mComments.length; i < n; i++) {
GalleryComment comment = mComments[i];
if (comment.id == result.id) {
position = i;
break;
}
}
if (-1 == position) {
Log.d(TAG, "Can't find comment with id " + result.id);
return;
}
// Update comment
GalleryComment comment = mComments[position];
comment.score = result.score;
if (result.expectVote > 0) {
comment.voteUp = 0 != result.vote;
} else {
comment.voteDown = 0 != result.vote;
}
mAdapter.notifyItemChanged(position);
}
private static class CommentGalleryListener extends EhCallback<GalleryCommentsScene, GalleryComment[]> {
public CommentGalleryListener(Context context, int stageId, String sceneTag) {
@@ -501,4 +623,37 @@ public final class GalleryCommentsScene extends ToolbarScene
return scene instanceof GalleryCommentsScene;
}
}
private static class VoteCommentListener extends EhCallback<GalleryCommentsScene, VoteCommentParser.Result> {
public VoteCommentListener(Context context, int stageId, String sceneTag) {
super(context, stageId, sceneTag);
}
@Override
public void onSuccess(VoteCommentParser.Result result) {
showTip(result.expectVote > 0 ?
(0 != result.vote ? R.string.vote_up_successfully : R.string.cancel_vote_up_successfully) :
(0 != result.vote ? R.string.vote_down_successfully : R.string.cancel_vote_down_successfully),
LENGTH_SHORT);
GalleryCommentsScene scene = getScene();
if (scene != null) {
scene.onVoteCommentSuccess(result);
}
}
@Override
public void onFailure(Exception e) {
showTip(R.string.vote_failed, LENGTH_SHORT);
}
@Override
public void onCancel() {}
@Override
public boolean isInstance(SceneFragment scene) {
return scene instanceof GalleryCommentsScene;
}
}
}
+2 -2
View File
@@ -136,7 +136,7 @@ public class Html {
*
* <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
*/
public static Spanned fromHtml(String source, ImageGetter imageGetter,
public static SpannableStringBuilder fromHtml(String source, ImageGetter imageGetter,
TagHandler tagHandler) {
Parser parser = new Parser();
try {
@@ -462,7 +462,7 @@ class HtmlToSpannedConverter implements ContentHandler {
mReader = parser;
}
public Spanned convert() {
public SpannableStringBuilder convert() {
mReader.setContentHandler(this);
try {