diff --git a/res/drawable-hdpi/ic_action_remove.png b/res/drawable-hdpi/ic_action_remove.png deleted file mode 100644 index e4c4327f4..000000000 Binary files a/res/drawable-hdpi/ic_action_remove.png and /dev/null differ diff --git a/res/drawable-hdpi/ic_action_reply.png b/res/drawable-hdpi/ic_action_reply.png new file mode 100644 index 000000000..6ffb54ef1 Binary files /dev/null and b/res/drawable-hdpi/ic_action_reply.png differ diff --git a/res/drawable-hdpi/ic_action_reply_dark.png b/res/drawable-hdpi/ic_action_reply_dark.png new file mode 100644 index 000000000..aaf186efb Binary files /dev/null and b/res/drawable-hdpi/ic_action_reply_dark.png differ diff --git a/res/drawable-mdpi/ic_action_remove.png b/res/drawable-mdpi/ic_action_remove.png deleted file mode 100644 index b08b2d49a..000000000 Binary files a/res/drawable-mdpi/ic_action_remove.png and /dev/null differ diff --git a/res/drawable-mdpi/ic_action_reply.png b/res/drawable-mdpi/ic_action_reply.png new file mode 100644 index 000000000..843714a30 Binary files /dev/null and b/res/drawable-mdpi/ic_action_reply.png differ diff --git a/res/drawable-mdpi/ic_action_reply_dark.png b/res/drawable-mdpi/ic_action_reply_dark.png new file mode 100644 index 000000000..8ad689774 Binary files /dev/null and b/res/drawable-mdpi/ic_action_reply_dark.png differ diff --git a/res/drawable-xhdpi/ic_action_remove.png b/res/drawable-xhdpi/ic_action_remove.png deleted file mode 100644 index 1f34ab43a..000000000 Binary files a/res/drawable-xhdpi/ic_action_remove.png and /dev/null differ diff --git a/res/drawable-xhdpi/ic_action_reply.png b/res/drawable-xhdpi/ic_action_reply.png new file mode 100644 index 000000000..34ba06546 Binary files /dev/null and b/res/drawable-xhdpi/ic_action_reply.png differ diff --git a/res/drawable-xhdpi/ic_action_reply_dark.png b/res/drawable-xhdpi/ic_action_reply_dark.png new file mode 100644 index 000000000..7933dd0b2 Binary files /dev/null and b/res/drawable-xhdpi/ic_action_reply_dark.png differ diff --git a/res/drawable-xxhdpi/ic_action_remove.png b/res/drawable-xxhdpi/ic_action_remove.png deleted file mode 100644 index 8dec2b837..000000000 Binary files a/res/drawable-xxhdpi/ic_action_remove.png and /dev/null differ diff --git a/res/drawable-xxhdpi/ic_action_reply.png b/res/drawable-xxhdpi/ic_action_reply.png new file mode 100644 index 000000000..6c45faebf Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_reply.png differ diff --git a/res/drawable-xxhdpi/ic_action_reply_dark.png b/res/drawable-xxhdpi/ic_action_reply_dark.png new file mode 100644 index 000000000..f652e1785 Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_reply_dark.png differ diff --git a/res/layout/search_view.xml b/res/layout/search_view.xml deleted file mode 100644 index 15c9627d8..000000000 --- a/res/layout/search_view.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/res/menu/detail.xml b/res/menu/detail.xml index 6a883b6ae..60267c05f 100644 --- a/res/menu/detail.xml +++ b/res/menu/detail.xml @@ -11,4 +11,10 @@ android:showAsAction="ifRoom" android:icon="@drawable/ic_action_download" android:title="@string/download"/> + + diff --git a/res/raw/change_log b/res/raw/change_log index e098e4298..53003f49b 100644 --- a/res/raw/change_log +++ b/res/raw/change_log @@ -6,6 +6,8 @@ Version 0.4.5 (2014-??-??) * 更规范的界面 * 添加评分功能 * 添加标签投票功能 +* 添加评论查看与发送功能 +* 评论按发布时间排序 * 调整下拉刷新控件 * 调整部分数据的存储方式 * 支持语音搜索 diff --git a/src/com/hippo/ehviewer/ListUrls.java b/src/com/hippo/ehviewer/ListUrls.java index e6fb6f177..1730d330d 100644 --- a/src/com/hippo/ehviewer/ListUrls.java +++ b/src/com/hippo/ehviewer/ListUrls.java @@ -185,28 +185,6 @@ public class ListUrls { return numPerPage; } - public boolean pageUp() { - if (page < max - 1) { - page++; - return true; - } - else { - page = max -1; - return false; - } - } - - public boolean pageDown() { - if (page > 0) { - page--; - return true; - } - else { - page = 0; - return false; - } - } - public String getUrl() { StringBuilder url = new StringBuilder(EhClient.listHeader); url.append("?"); diff --git a/src/com/hippo/ehviewer/activity/CommentsSectionFragment.java b/src/com/hippo/ehviewer/activity/CommentsSectionFragment.java index 9433af1f8..2a8c6383f 100644 --- a/src/com/hippo/ehviewer/activity/CommentsSectionFragment.java +++ b/src/com/hippo/ehviewer/activity/CommentsSectionFragment.java @@ -19,6 +19,7 @@ import android.widget.TextView; public class CommentsSectionFragment extends Fragment { + @SuppressWarnings("unused") private static final String TAG = "CommentsSectionFragment"; private MangaDetailActivity mActivity; @@ -101,16 +102,34 @@ public class CommentsSectionFragment extends Fragment { public long getItemId(int position) { return position; } - + @Override public View getView(int position, View convertView, ViewGroup parent) { + boolean isUserSame = true; + boolean isTimeSame = true; + if (convertView == null) convertView = LayoutInflater.from(mActivity) .inflate(R.layout.comments_item, null); Comment c = mComments.get(position); - ((TextView)convertView.findViewById(R.id.user)).setText(c.user); - ((TextView)convertView.findViewById(R.id.time)).setText(c.time); - ((TextView)convertView.findViewById(R.id.comment)).setText(Html.fromHtml(c.comment)); + + TextView user = (TextView)convertView.findViewById(R.id.user); + if (!c.user.equals(user.getText())) { + isUserSame = false; + user.setText(c.user); + } + + TextView time = (TextView)convertView.findViewById(R.id.time); + if (!c.time.equals(time.getText())) { + isTimeSame = false; + time.setText(c.time); + } + + // No one can post one comment at same this time + if (!isUserSame || !isTimeSame) + ((TextView)convertView.findViewById(R.id.comment)) + .setText(Html.fromHtml(c.comment)); + return convertView; } }; diff --git a/src/com/hippo/ehviewer/activity/DetailSectionFragment.java b/src/com/hippo/ehviewer/activity/DetailSectionFragment.java index 6ec916b83..cb3836cb3 100644 --- a/src/com/hippo/ehviewer/activity/DetailSectionFragment.java +++ b/src/com/hippo/ehviewer/activity/DetailSectionFragment.java @@ -684,10 +684,6 @@ public class DetailSectionFragment extends Fragment public void onSuccess(GalleryDetail md) { Cache.mdCache.put(String.valueOf(mGalleryDetail.gid), md); layout(md); - - for (Comment c : mGalleryDetail.comments) { - Log.d(TAG, c.time); - } } @Override diff --git a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java index d6fc1219f..f8b0ca6ff 100644 --- a/src/com/hippo/ehviewer/activity/MangaDetailActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaDetailActivity.java @@ -70,6 +70,7 @@ import android.view.animation.TranslateAnimation; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.Button; +import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RatingBar; @@ -94,6 +95,8 @@ public class MangaDetailActivity extends FragmentActivity private DetailSectionFragment mDetailFragment; private CommentsSectionFragment mCommentsFragment; + private int mTabIndex; + private DownloadServiceConnection mServiceConn = new DownloadServiceConnection(); @Override @@ -162,6 +165,8 @@ public class MangaDetailActivity extends FragmentActivity @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { mViewPager.setCurrentItem(tab.getPosition()); + mTabIndex = tab.getPosition(); + invalidateOptionsMenu(); } @Override @@ -192,8 +197,6 @@ public class MangaDetailActivity extends FragmentActivity mCommentsFragment.setComments(comments); } - /* - @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection @@ -202,12 +205,13 @@ public class MangaDetailActivity extends FragmentActivity finish(); return true; case R.id.action_favourite: - mData.addLocalFavourite(mangaDetail); + ((AppContext)getApplication()).getData().addLocalFavourite(mGalleryInfo); Toast.makeText(MangaDetailActivity.this, getString(R.string.toast_add_favourite), Toast.LENGTH_SHORT).show(); return true; case R.id.action_download: + /* Intent it = new Intent(MangaDetailActivity.this, DownloadService.class); startService(it); if (mangaDetail.firstPage == null) @@ -222,13 +226,63 @@ public class MangaDetailActivity extends FragmentActivity Toast.makeText(MangaDetailActivity.this, getString(R.string.toast_add_download), Toast.LENGTH_SHORT).show(); + */ + return true; + + case R.id.action_reply: + final EditText et = new EditText(this); + //et.setMinimumHeight(Ui.dp2pix(64)); + LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + int x = Ui.dp2pix(8); + lp.leftMargin = x; + lp.rightMargin = x; + lp.topMargin = x; + lp.bottomMargin = x; + new DialogBuilder(this).setView(et, lp) + .setTitle("评论") + .setPositiveButton("发送", new View.OnClickListener() { + @Override + public void onClick(View v) { + ((AlertButton)v).dialog.dismiss(); + String comment = et.getText().toString(); + ((AppContext)getApplication()).getEhClient() + .comment(EhClient.getDetailUrl(mGalleryInfo.gid, mGalleryInfo.token, EhClient.EX), + comment, new EhClient.OnCommentListener() { + @Override + public void onSuccess(List comments) { + setComments(comments); + } + @Override + public void onFailure(String eMsg) { + Toast.makeText(MangaDetailActivity.this, eMsg, Toast.LENGTH_SHORT).show(); + } + }); + } + }).setNegativeButton(android.R.string.cancel, + new View.OnClickListener() { + @Override + public void onClick(View v) { + ((AlertButton)v).dialog.dismiss(); + } + }).create().show(); + return true; default: return super.onOptionsItemSelected(item); } } - */ + @Override + public boolean onPrepareOptionsMenu (Menu menu) { + MenuItem reply = menu.findItem(R.id.action_reply); + if (mTabIndex == 1) + reply.setVisible(true); + else + reply.setVisible(false); + return true; + } private class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { diff --git a/src/com/hippo/ehviewer/activity/MangaListActivity.java b/src/com/hippo/ehviewer/activity/MangaListActivity.java index 01303161b..4c16ef639 100644 --- a/src/com/hippo/ehviewer/activity/MangaListActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaListActivity.java @@ -1293,7 +1293,7 @@ public class MangaListActivity extends SlidingActivity { mHlv.setOnFooterRefreshListener(new HfListView.OnFooterRefreshListener() { @Override public boolean onFooterRefresh() { - if (lus.pageUp()) { + if (lus.setPage(lastPage+1)) { mGetMode = NEXT_PAGE; getList(); return true; diff --git a/src/com/hippo/ehviewer/data/Data.java b/src/com/hippo/ehviewer/data/Data.java index 7a703c89d..9c9780c8c 100644 --- a/src/com/hippo/ehviewer/data/Data.java +++ b/src/com/hippo/ehviewer/data/Data.java @@ -513,7 +513,7 @@ public class Data { public synchronized void addLocalFavourite(GalleryInfo galleryInfo) { int gid = galleryInfo.gid; - if (containsRead(gid)) { + if (containsLocalFavourite(gid)) { updateGallery(galleryInfo); } else { addGallery(galleryInfo); diff --git a/src/com/hippo/ehviewer/ehclient/DetailParser.java b/src/com/hippo/ehviewer/ehclient/DetailParser.java index 913083ea8..0335f0ce4 100644 --- a/src/com/hippo/ehviewer/ehclient/DetailParser.java +++ b/src/com/hippo/ehviewer/ehclient/DetailParser.java @@ -1,5 +1,7 @@ package com.hippo.ehviewer.ehclient; +import java.util.Collections; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.AbstractMap.SimpleEntry; import java.util.LinkedList; @@ -25,6 +27,8 @@ public class DetailParser { public static final int OFFENSIVE = 0x20; public static final int PINING = 0x40; + private static final CommentSort cs = new CommentSort(); + private int mMode; public int category; @@ -141,8 +145,10 @@ public class DetailParser { m = p.matcher(pageContent); comments = new LinkedList(); while (m.find()) { + re |= COMMENT; comments.add(new Comment(m.group(1), m.group(2), m.group(3))); } + Collections.sort(comments, cs); } return re; } @@ -188,4 +194,68 @@ public class DetailParser { type = ListUrls.UNKNOWN; return type; } + + static class CommentSort implements Comparator { + private int compareNum(String n1, String n2, int median) { + int re = 0; + for (int i = 0; i < median; i++) { + re *= 10; + re += n1.charAt(i) - n2.charAt(i); + } + return re; + } + private int getMonth(String m) { + if (m.equals("January")) + return 1; + else if (m.equals("February")) + return 2; + else if (m.equals("March")) + return 3; + else if (m.equals("April")) + return 4; + else if (m.equals("May")) + return 5; + else if (m.equals("June")) + return 6; + else if (m.equals("July")) + return 7; + else if (m.equals("August")) + return 8; + else if (m.equals("September")) + return 9; + else if (m.equals("October")) + return 10; + else if (m.equals("November")) + return 11; + else if (m.equals("December")) + return 12; + else + return 0; + } + + @Override + public int compare(Comment c1, Comment c2) { + int re = 0; + Pattern p = Pattern.compile("(\\d{2}) (\\w+) (\\d{4}), (\\d{2}):(\\d{2})"); + Matcher m1 = p.matcher(c1.time); + Matcher m2 = p.matcher(c2.time); + if (!m1.find() || !m2.find()) + return 0; + // year + re += compareNum(m1.group(3), m2.group(3), 4); + re <<= 4; + // Month + re += getMonth(m1.group(2)) - getMonth(m2.group(2)); + re <<= 5; + // Day + re += compareNum(m1.group(1), m2.group(1), 2); + re <<= 5; + // Hour + re += compareNum(m1.group(4), m2.group(4), 2); + re <<= 6; + // Minute + re += compareNum(m1.group(5), m2.group(5), 2); + return re; + } + } } diff --git a/src/com/hippo/ehviewer/ehclient/EhClient.java b/src/com/hippo/ehviewer/ehclient/EhClient.java index a20a7480d..d587eec8b 100644 --- a/src/com/hippo/ehviewer/ehclient/EhClient.java +++ b/src/com/hippo/ehviewer/ehclient/EhClient.java @@ -14,6 +14,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1516,6 +1517,44 @@ public class EhClient { } + // Post comment + public interface OnCommentListener { + void onSuccess(List comments); + void onFailure(String eMsg); + } + + public void comment(final String detailUrl, final String comment, + final OnCommentListener listener) { + new Thread(new Runnable() { + @Override + public void run() { + HttpHelper hp = new HttpHelper(mAppContext); + hp.setOnRespondListener(new HttpHelper.OnRespondListener() { + @Override + public void onSuccess(String pageContent) { + DetailParser parser = new DetailParser(); + parser.setMode(DetailParser.COMMENT); + if (parser.parser(pageContent) == DetailParser.COMMENT) { + listener.onSuccess(parser.comments); + } else { + listener.onFailure("parser error"); // TODO + } + } + + @Override + public void onFailure(String eMsg) { + listener.onFailure(eMsg); // TODO + } + }); + hp.post(detailUrl, new String[][]{ + new String[]{"commenttext", comment}, + new String[]{"postcomment", "Post New"}}); + } + }).start(); + } + + // TODO + /********** Use E-hentai API ************/ // rate for gallery diff --git a/src/com/hippo/ehviewer/network/HttpHelper.java b/src/com/hippo/ehviewer/network/HttpHelper.java index aafcf796c..fbd53cc68 100644 --- a/src/com/hippo/ehviewer/network/HttpHelper.java +++ b/src/com/hippo/ehviewer/network/HttpHelper.java @@ -336,6 +336,7 @@ public class HttpHelper { return null; } + /* public String post(String urlStr, String str) { mException = null; @@ -420,7 +421,7 @@ public class HttpHelper { mException = new RedirectionException(); return null; } - + */ public String postJson(String urlStr, JSONObject json) { mException = null; diff --git a/src/com/hippo/ehviewer/view/SearchView.java b/src/com/hippo/ehviewer/view/SearchView.java deleted file mode 100644 index d77ac352f..000000000 --- a/src/com/hippo/ehviewer/view/SearchView.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.hippo.ehviewer.view; - -import com.hippo.ehviewer.R; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.widget.LinearLayout; - -public class SearchView extends LinearLayout { - public SearchView(Context context) { - super(context, null); - } - - public SearchView(Context context, AttributeSet attrs) { - super(context, attrs); - - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(R.layout.search_view, this, true); - } - - -} diff --git a/src/com/hippo/ehviewer/view/TagListView.java b/src/com/hippo/ehviewer/view/TagListView.java index b59179997..d5b15d2f5 100644 --- a/src/com/hippo/ehviewer/view/TagListView.java +++ b/src/com/hippo/ehviewer/view/TagListView.java @@ -366,12 +366,12 @@ public class TagListView extends ListView { int deltaY = mLastEventY - mDownY; if (mCellIsMobile) { - if (deltaX < -mHoverCellOriginalBounds.width() / SENSITY) + if (deltaX > mHoverCellOriginalBounds.width() / SENSITY) mIsDelete = true; else mIsDelete = false; - if (deltaX > mHoverCellOriginalBounds.width() / SENSITY) + if (deltaX < -mHoverCellOriginalBounds.width() / SENSITY) mIsModify = true; else mIsModify = false; diff --git a/src/com/hippo/ehviewer/widget/DialogBuilder.java b/src/com/hippo/ehviewer/widget/DialogBuilder.java index 3f47a7eed..b3ffbd6d2 100644 --- a/src/com/hippo/ehviewer/widget/DialogBuilder.java +++ b/src/com/hippo/ehviewer/widget/DialogBuilder.java @@ -103,20 +103,25 @@ public class DialogBuilder extends AlertDialog.Builder { * @return */ public DialogBuilder setView(View view, boolean center) { + LinearLayout.LayoutParams lp; + if (center) { + lp = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER; + } else { + lp = new LinearLayout.LayoutParams( + LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); + } + setView(view, lp); + return this; + } + + public DialogBuilder setView(View view, LinearLayout.LayoutParams lp) { ScrollView scrollView = (ScrollView)mView.findViewById(R.id.scroll_view); scrollView.setVisibility(View.VISIBLE); LinearLayout customLayout = (LinearLayout)mView.findViewById(R.id.custom); customLayout.setVisibility(View.VISIBLE); - if (center) { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - customLayout.addView(view, lp); - } else { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); - customLayout.addView(view, lp); - } + customLayout.addView(view, lp); return this; }