Improve detail scene

This commit is contained in:
seven332 committed 2015-07-02 01:21:07 +08:00
1 parent a01e43ea95
commit 3f6d3ea21c
47 files changed
+1647 -89

No files matched your search

@@ -0,0 +1,37 @@
/*
* Copyright 2015 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.animation;
import android.animation.TimeInterpolator;
public class DurationInterpolator implements TimeInterpolator {
private float mDuration;
public DurationInterpolator(float duration) {
mDuration = duration;
}
@Override
public float getInterpolation(float input) {
if (input > mDuration) {
return (input - mDuration) / (1 - mDuration);
} else {
return 0f;
}
}
}
@@ -5,4 +5,18 @@ public class EhImageKeyFactory {
public static String getThumbKey(int gid) {
return "thumb:" + gid;
}
/**
* @param index start from 0
*/
public static String getNormalPreviewKey(int gid, int index) {
return "preview:normal:" + gid + ":" + index;
}
/**
* @param index start from 0
*/
public static String getLargePreviewKey(int gid, int index) {
return "preview:large:" + gid + ":" + index;
}
}
@@ -19,8 +19,9 @@ package com.hippo.ehviewer.client;
import android.os.AsyncTask;
import android.os.Process;
import com.hippo.ehviewer.data.GalleryDetail;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.network.EhOkHttpClient;
import com.hippo.network.ResponseCodeException;
import com.hippo.util.PriorityThreadFactory;
@@ -426,6 +427,10 @@ public final class EhClient {
gd.tags = parser.tags;
gd.comments = parser.comments;
gd.previewPageCount = parser.previewPageCount;
gd.previewSetArray = new PreviewSet[gd.previewPageCount];
gd.previewSetArray[0] = parser.previewSet;
gd.previewSetArray[0].setStartIndex(0);
gd.previewSetArray[0].setGid(gd.gid);
return gd;
}
@@ -16,8 +16,11 @@
package com.hippo.ehviewer.client;
import com.hippo.ehviewer.data.Comment;
import com.hippo.ehviewer.data.TagGroup;
import com.hippo.ehviewer.client.data.Comment;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.client.data.NormalPreviewSet;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.client.data.TagGroup;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.util.AssertUtils;
import com.hippo.util.Utils;
@@ -52,6 +55,7 @@ public class GalleryDetailParser {
public static final int REQUEST_DETAIL = 0x1;
public static final int REQUEST_TAG = 0x2;
public static final int REQUEST_PREVIEW_INFO = 0x4;
public static final int REQUEST_PREVIEW = 0x8;
public static final int REQUEST_COMMENT = 0x10;
private static final CommentSort COMMENT_SORTER = new CommentSort();
@@ -84,6 +88,8 @@ public class GalleryDetailParser {
public int previewPageCount;
public PreviewSet previewSet;
private String sortOut(String str) {
// Avoid null
if (str == null) {
@@ -104,6 +110,36 @@ public class GalleryDetailParser {
}
}
private void parseNormalPreview(String body) {
Pattern p = Pattern.compile("<div[^<>]*class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*>");
Matcher m = p.matcher(body);
NormalPreviewSet normalPreviewSet = new NormalPreviewSet();
while (m.find()) {
normalPreviewSet.addItem(m.group(3), Integer.parseInt(m.group(4)), 0,
Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
m.group(5));
}
previewSet = normalPreviewSet;
}
private void parseLargePreview(String body) {
Pattern p = Pattern.compile("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img.+?src=\"(.+?)\"");
Matcher m = p.matcher(body);
LargePreviewSet largePreviewSet = new LargePreviewSet();
while (m.find()) {
largePreviewSet.addItem(m.group(2), m.group(1));
}
previewSet = largePreviewSet;
}
private void parsePreview(String body) {
if (body.contains("<div class=\"gdtm\"")) {
parseNormalPreview(body);
} else {
parseLargePreview(body);
}
}
private void parse(String body, int request) throws EhException {
Pattern p;
Matcher m;
@@ -240,6 +276,11 @@ public class GalleryDetailParser {
}
}
// Get preview
if ((request & REQUEST_PREVIEW_INFO) != 0) {
parsePreview(body);
}
// Get comment
if ((request & REQUEST_COMMENT) != 0) {
p = Pattern.compile("<div class=\"c3\">Posted on ([^<>]+) by: &nbsp; <a[^<>]+>([^<>]+)</a>.+?<div class=\"c6\"[^>]*>(.+?)</div><div class=\"c[78]\"");
@@ -258,6 +299,10 @@ public class GalleryDetailParser {
}
Collections.sort(comments, COMMENT_SORTER);
}
if ((request & REQUEST_COMMENT) != 0) {
}
}
public void parse(String body, int request, int source) throws Exception {
@@ -16,8 +16,8 @@
package com.hippo.ehviewer.client;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.data.LofiGalleryInfo;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.LofiGalleryInfo;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.util.AssertException;
import com.hippo.util.AssertUtils;
@@ -16,7 +16,7 @@
package com.hippo.ehviewer.client;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.util.Utils;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import java.util.Date;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import java.util.List;
@@ -46,4 +46,5 @@ public class GalleryDetail extends GalleryInfo {
public int previewPageCount;
public PreviewSet[] previewSetArray;
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import android.os.Parcel;
import android.os.Parcelable;
@@ -0,0 +1,78 @@
/*
* Copyright 2015 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.data;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
import com.hippo.conaco.Conaco;
import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.ehviewer.widget.LoadImageView;
import com.hippo.widget.SimpleGridLayout;
import java.util.ArrayList;
import java.util.List;
public class LargePreviewSet extends PreviewSet {
private List<Item> mItemList = new ArrayList<>();
@Override
public int size() {
return mItemList.size();
}
public void addItem(String imageUrl, String pageUrl) {
mItemList.add(new Item(imageUrl, pageUrl));
}
@Override
public void bindView(SimpleGridLayout simpleGridLayout, LayoutInflater inflater, Conaco conaco) {
ensureViewGroup(simpleGridLayout, inflater);
int size = mItemList.size();
for (int i = 0; i < size; i++) {
final Item item = mItemList.get(i);
final int index = i + getStartIndex();
final ViewGroup viewGroup = (ViewGroup) simpleGridLayout.getChildAt(i);
conaco.load((LoadImageView) viewGroup.getChildAt(0),
EhImageKeyFactory.getLargePreviewKey(getGid(), index), item.imageUrl);
((TextView) viewGroup.getChildAt(1)).setText(Integer.toString(index + 1));
}
}
@Override
public void cancelLoadTask(SimpleGridLayout simpleGridLayout, Conaco conaco) {
int count = simpleGridLayout.getChildCount();
for (int i = 0; i < count; i++) {
final ViewGroup viewGroup = (ViewGroup) simpleGridLayout.getChildAt(i);
conaco.cancel((LoadImageView) viewGroup.getChildAt(0));
}
}
private class Item {
public String imageUrl;
public String pageUrl;
public Item(String imageUrl, String pageUrl) {
this.imageUrl = imageUrl;
this.pageUrl = pageUrl;
}
}
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.util.EhUtils;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import android.os.Parcel;
@@ -0,0 +1,230 @@
/*
* Copyright 2015 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.data;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.hippo.conaco.BitmapHolder;
import com.hippo.conaco.Conaco;
import com.hippo.conaco.Unikery;
import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.util.Log;
import com.hippo.widget.SimpleGridLayout;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class NormalPreviewSet extends PreviewSet {
private List<Row> mRowArray = new ArrayList<>();
private Set<LoadImageTask> mLoadImageTasks = new HashSet<>();
@Override
public int size() {
int size = 0;
for (Row row : mRowArray) {
size += row.itemArray.size();
}
return size;
}
public void addItem(String imageUrl, int xOffset, int yOffset, int width,
int height, String url) {
Row row;
int size = mRowArray.size();
if (size == 0 || ! (row = mRowArray.get(size - 1)).imageUrl.equals(imageUrl)) {
row = new Row(imageUrl);
mRowArray.add(row);
}
row.addItem(xOffset, yOffset, width, height, url);
}
@Override
public void bindView(SimpleGridLayout simpleGridLayout,
LayoutInflater inflater, Conaco conaco) {
ensureViewGroup(simpleGridLayout, inflater);
int i = 0;
for (Row row : mRowArray) {
int rowSize = row.itemArray.size();
ImageView[] imageViews = new ImageView[rowSize];
for (int j = 0; j < rowSize; j++) {
ViewGroup viewGroup = (ViewGroup) simpleGridLayout.getChildAt(i);
imageViews[j] = (ImageView) viewGroup.getChildAt(0);
((TextView) viewGroup.getChildAt(1)).setText(Integer.toString(i + getStartIndex() + 1));
i++;
}
LoadImageTask loadImageTask = new LoadImageTask(row, imageViews);
mLoadImageTasks.add(loadImageTask);
String key;
if (row.imageIndex != -1) {
key = EhImageKeyFactory.getNormalPreviewKey(getGid(), row.imageIndex);
} else {
key = row.imageUrl;
}
conaco.load(loadImageTask, key, row.imageUrl);
}
}
@Override
public void cancelLoadTask(SimpleGridLayout simpleGridLayout, Conaco conaco) {
for (LoadImageTask loadImageTask : mLoadImageTasks) {
conaco.cancel(loadImageTask);
}
mLoadImageTasks.clear();
}
class LoadImageTask implements Unikery {
private int mTaskId;
private Row mRow;
private ImageView[] mImageViews;
public LoadImageTask(Row row, ImageView[] imageViews) {
mRow = row;
mImageViews = imageViews;
}
@Override
public void setBitmap(BitmapHolder bitmapHolder, Conaco.Source source) {
bitmapHolder.obtain();
Bitmap bitmap = bitmapHolder.getBitmap();
int maxWidth = bitmap.getWidth();
int maxHeight = bitmap.getHeight();
int size = mRow.itemArray.size();
for(int i = 0; i < size; i++) {
Item item = mRow.itemArray.get(i);
if (item.xOffset + item.width > maxWidth) {
item.width = maxWidth - item.xOffset;
if (item.width <= 0) {
// Bad area
continue;
}
}
if (item.yOffset + item.height > maxHeight) {
item.height = maxHeight - item.yOffset;
if (item.height <= 0) {
// Bad area
continue;
}
}
Bitmap previewBitmap = Bitmap.createBitmap(bitmap, item.xOffset,
item.yOffset, item.width, item.height);
if (source != Conaco.Source.MEMORY) {
Drawable[] layers = new Drawable[2];
layers[0] = new ColorDrawable(Color.TRANSPARENT);
layers[1] = new BitmapDrawable(mImageViews[i].getResources(), previewBitmap);
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
mImageViews[i].setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(300);
} else {
mImageViews[i].setImageBitmap(previewBitmap);
}
}
bitmapHolder.release();
mLoadImageTasks.remove(this);
}
@Override
public void setDrawable(Drawable drawable) {
// Empty
}
@Override
public void setTaskId(int id) {
mTaskId = id;
}
@Override
public int getTaskId() {
return mTaskId;
}
@Override
public void onFailure() {
// TODO
mLoadImageTasks.remove(this);
}
@Override
public void onCancel() {
// Empty
}
}
class Row {
public String imageUrl;
public List<Item> itemArray = new ArrayList<>();
public int imageIndex;
public Row(String imageUrl) {
this.imageUrl = imageUrl;
int index1 = imageUrl.lastIndexOf('-');
int index2 = imageUrl.lastIndexOf('.');
try {
imageIndex = Integer.parseInt(imageUrl.substring(index1 + 1, index2)) - 1;
} catch (Exception e) {
Log.w("Can't get normal preview index", e);
imageIndex = -1;
}
}
public void addItem(int xOffset, int yOffset, int width, int height,
String url) {
itemArray.add(new Item(xOffset, yOffset, width, height, url));
}
}
class Item {
public int xOffset;
public int yOffset;
public int width;
public int height;
public String url;
public Item(int xOffset, int yOffset, int width, int height, String url) {
this.xOffset = xOffset;
this.yOffset = yOffset;
this.width = width;
this.height = height;
this.url = url;
}
}
}
@@ -0,0 +1,68 @@
/*
* Copyright 2015 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.data;
import android.view.LayoutInflater;
import com.hippo.conaco.Conaco;
import com.hippo.ehviewer.R;
import com.hippo.widget.SimpleGridLayout;
public abstract class PreviewSet {
private int mStartIndex;
private int mGid;
public void setStartIndex(int startIndex) {
mStartIndex = startIndex;
}
public int getStartIndex() {
return mStartIndex;
}
public abstract int size();
public void setGid(int gid) {
mGid = gid;
}
public int getGid() {
return mGid;
}
public abstract void bindView(SimpleGridLayout simpleGridLayout,
LayoutInflater inflater, Conaco conaco);
protected void ensureViewGroup(SimpleGridLayout simpleGridLayout, LayoutInflater inflater) {
int size = size();
int diff = size - simpleGridLayout.getChildCount();
if (diff > 0) {
for (int i = 0; i < diff; i++) {
inflater.inflate(R.layout.item_preview, simpleGridLayout, true);
}
} else if (diff < 0) {
diff = -diff;
for (int i = 0; i < diff; i++) {
simpleGridLayout.removeViews(size, diff);
}
}
}
public abstract void cancelLoadTask(SimpleGridLayout simpleGridLayout, Conaco conaco);
}
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
import java.util.ArrayList;
import java.util.List;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.hippo.ehviewer.data;
package com.hippo.ehviewer.client.data;
public class UnsupportedSearchException extends Exception {
@@ -13,7 +13,7 @@ import android.widget.TextView;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.data.Comment;
import com.hippo.ehviewer.client.data.Comment;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.Announcer;
import com.hippo.scene.AppbarScene;
@@ -39,26 +39,36 @@ import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.data.Comment;
import com.hippo.ehviewer.data.GalleryDetail;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.data.TagGroup;
import com.hippo.ehviewer.client.EhException;
import com.hippo.ehviewer.client.OffensiveException;
import com.hippo.ehviewer.client.data.Comment;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.TagGroup;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.widget.LoadImageView;
import com.hippo.ehviewer.widget.PreviewLayout;
import com.hippo.ehviewer.widget.RatingView;
import com.hippo.miscellaneous.StartActivityHelper;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.Announcer;
import com.hippo.scene.RippleCurtain;
import com.hippo.scene.Scene;
import com.hippo.scene.SimpleDialog;
import com.hippo.util.Log;
import com.hippo.util.URLImageGetter;
import com.hippo.util.UiUtils;
import com.hippo.util.ViewUtils;
import com.hippo.widget.AccurateClick;
import com.hippo.widget.AutoWrapLayout;
import java.util.List;
public class GalleryDetailScene extends Scene implements View.OnClickListener {
import static com.hippo.ehviewer.R.id.no_tags;
public class GalleryDetailScene extends Scene implements View.OnClickListener,
AccurateClick.OnAccurateClickListener {
public static final String KEY_GALLERY_INFO = "gallery_info";
@@ -88,8 +98,10 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
private TextView mShare;
private TextView mRate;
private LinearLayout mTag;
private TextView mNoTags;
private LinearLayout mComment;
private TextView mCommentMore;
private PreviewLayout mPreviewLayout;
private View mProgressBar;
@@ -97,6 +109,12 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
private GalleryDetail mGalleryDetail;
private void requestGalleryDetail(GalleryInfo gi) {
EhClient.getInstance().getGalleryDetail(Config.getEhSource(),
EhClient.getDetailUrl(Config.getEhSource(), gi.gid, gi.token, 0),
new EhDetailListener());
}
private void handleAnnouncer(Announcer announcer) {
GalleryInfo gi;
@@ -112,9 +130,7 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
mCategory.setText(EhUtils.getCategory(gi.category));
mCategory.setTextColor(EhUtils.getCategoryColor(gi.category));
EhClient.getInstance().getGalleryDetail(Config.getEhSource(),
EhClient.getDetailUrl(Config.getEhSource(), gi.gid, gi.token, 0),
new EhDetailListener());
requestGalleryDetail(gi);
}
Context context = getStageActivity();
@@ -146,7 +162,8 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
mTorrent.setOnClickListener(this);
mShare.setOnClickListener(this);
mRate.setOnClickListener(this);
mCommentMore.setOnClickListener(this);
AccurateClick.setOnAccurateClickListener(mComment, this);
RippleSalon.addRipple(mRead, false);
RippleSalon.addRipple(mDownload, false);
@@ -187,8 +204,10 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
mShare = (TextView) mContent.findViewById(R.id.share);
mRate = (TextView) mContent.findViewById(R.id.rate);
mTag = (LinearLayout) mContent.findViewById(R.id.tag);
mNoTags = (TextView) mTag.findViewById(no_tags);
mComment = (LinearLayout) mContent.findViewById(R.id.comment);
mCommentMore = (TextView) mContent.findViewById(R.id.comment_more);
mPreviewLayout = (PreviewLayout) mContent.findViewById(R.id.preview);
mProgressBar = findViewById(R.id.progress_bar);
@@ -220,10 +239,23 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
} else if (v == mShare) {
StartActivityHelper.share(getStageActivity(),
EhClient.getDetailUrl(Config.getEhSource(), gd.gid, gd.token, 0));
} else if (v == mCommentMore) {
}
}
@Override
public void onAccurateClick(View v, float x, float y) {
GalleryDetail gd = mGalleryDetail;
if (gd == null) {
return;
}
if (v == mComment) {
int[] position = new int[2];
ViewUtils.getLocationInAncestor(mComment, position, getSceneView());
Announcer announcer = new Announcer();
announcer.setObject(mGalleryDetail.comments);
startScene(CommentScene.class, announcer);
startScene(CommentScene.class, announcer,
new RippleCurtain((int) x + position[0], (int) y + position[1]));
}
}
@@ -272,31 +304,34 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
}
private void fillTags(List<TagGroup> tags) {
Context context = getStageActivity();
LayoutInflater inflater = getStageActivity().getLayoutInflater();
int x = UiUtils.dp2pix(context, 2);
int y = UiUtils.dp2pix(context, 4);
if (tags.size() != 0) {
mNoTags.setVisibility(View.GONE);
for (TagGroup tagGroup : tags) {
LinearLayout tagGroupLayout = new LinearLayout(context);
tagGroupLayout.setOrientation(LinearLayout.HORIZONTAL);
AutoWrapLayout tagLayout = new AutoWrapLayout(context);
Context context = getStageActivity();
LayoutInflater inflater = getStageActivity().getLayoutInflater();
int x = UiUtils.dp2pix(context, 2);
int y = UiUtils.dp2pix(context, 4);
// Group name
@SuppressLint("InflateParams")
TextView groupNameView = (TextView) inflater.inflate(R.layout.tag_group, null);
groupNameView.setText(tagGroup.groupName);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(x, y, x, y);
tagGroupLayout.addView(groupNameView, lp);
for (TagGroup tagGroup : tags) {
LinearLayout tagGroupLayout = new LinearLayout(context);
tagGroupLayout.setOrientation(LinearLayout.HORIZONTAL);
AutoWrapLayout tagLayout = new AutoWrapLayout(context);
int count = tagGroup.getTagCount();
for (int i = 0; i < count; i++) {
// Group name
@SuppressLint("InflateParams")
TextView tagView = (TextView) inflater.inflate(R.layout.tag, null);
tagView.setText(tagGroup.getTagAt(i));
TextView groupNameView = (TextView) inflater.inflate(R.layout.tag_group, null);
groupNameView.setText(tagGroup.groupName);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(x, y, x, y);
tagGroupLayout.addView(groupNameView, lp);
int count = tagGroup.getTagCount();
for (int i = 0; i < count; i++) {
@SuppressLint("InflateParams")
TextView tagView = (TextView) inflater.inflate(R.layout.tag, null);
tagView.setText(tagGroup.getTagAt(i));
/*
tagView.setOnClickListener(new View.OnClickListener() {
@Override
@@ -312,17 +347,21 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
}
});
*/
AutoWrapLayout.LayoutParams alp = new AutoWrapLayout.LayoutParams();
alp.setMargins(x, y, x, y);
tagLayout.addView(tagView, alp);
AutoWrapLayout.LayoutParams alp = new AutoWrapLayout.LayoutParams();
alp.setMargins(x, y, x, y);
tagLayout.addView(tagView, alp);
}
tagGroupLayout.addView(tagLayout);
mTag.addView(tagGroupLayout);
}
tagGroupLayout.addView(tagLayout);
mTag.addView(tagGroupLayout);
} else {
mNoTags.setVisibility(View.VISIBLE);
}
}
@SuppressLint("InflateParams")
private View createCommentView(Comment comment) {
View view = LayoutInflater.from(getStageActivity()).inflate(R.layout.item_comment, null);
View view = LayoutInflater.from(getStageActivity()).inflate(R.layout.item_comment, null);
((TextView) view.findViewById(R.id.user)).setText(comment.user);
((TextView) view.findViewById(R.id.time)).setText(comment.time);
TextView commentText = (TextView) view.findViewById(R.id.comment);
@@ -364,11 +403,13 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
int commentNum = galleryDetail.comments.size();
if (commentNum == 0) {
mCommentMore.setText("暂无评论");
mCommentMore.setText(R.string.no_comments);
// Remove padding interval
mCommentMore.setPadding(0, 0, 0, 0);
} else if (commentNum <= 2){
mCommentMore.setText("暂无更多评论");
mCommentMore.setText(R.string.no_more_comments);
} else {
mCommentMore.setText("更多评论");
mCommentMore.setText(R.string.more_comment);
}
int maxShown = Math.min(2, commentNum);
for (int i = 0; i < maxShown; i++) {
@@ -377,13 +418,30 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener {
LinearLayout.LayoutParams.WRAP_CONTENT));
}
mPreviewLayout.setData(galleryDetail.previewSetArray,
getStageActivity().getLayoutInflater(),
EhApplication.getConaco(getStageActivity()));
mPreviewLayout.selectPreviewAt(0);
mViewTransition.showView(0);
}
@Override
public void onFailure(Exception e) {
e.printStackTrace();
// TODO
if (e instanceof OffensiveException) {
} else if (e instanceof EhException) {
new SimpleDialog.Builder(getStageActivity()).setTitle("Error")
.setMessage(e.getMessage())
.setNegativeButton(android.R.string.cancel)
.setOnCloseListener(new SimpleDialog.OnCloseListener() {
@Override
public void onClose(SimpleDialog dialog, boolean cancel) {
finish();
}
}).show();
}
}
}
}
@@ -47,9 +47,9 @@ import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.GalleryListParser;
import com.hippo.ehviewer.data.GalleryInfo;
import com.hippo.ehviewer.data.ListUrlBuilder;
import com.hippo.ehviewer.data.UnsupportedSearchException;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.data.UnsupportedSearchException;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.EhUtils;
@@ -7,13 +7,13 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import com.hippo.conaco.BitmapHolder;
import com.hippo.conaco.Conaco;
import com.hippo.conaco.Unikery;
import com.hippo.widget.FixedAspectImageView;
public class LoadImageView extends ImageView implements Unikery {
public class LoadImageView extends FixedAspectImageView implements Unikery {
private int mTaskId = Unikery.INVAILD_ID;
@@ -0,0 +1,220 @@
/*
* Copyright 2015 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.widget;
import android.content.Context;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.hippo.conaco.Conaco;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.rippleold.RippleSalon;
import com.hippo.widget.SimpleGridLayout;
public final class PreviewLayout extends LinearLayout implements View.OnClickListener {
private GestureDetector mGestureDetector;
private PreviewSet[] mPreviewSets;
private Conaco mConaco;
private LayoutInflater mInflater;
private int mPreviewSetCount;
private int mCurrentPreviewIndex = -1;
private SimpleGridLayout mSimpleGridLayout;
private View mTopPrevious;
private TextView mTopSelection;
private View mTopNext;
private View mBottomPrevious;
private TextView mBottomSelection;
private View mBottomNext;
private int mWidth;
public PreviewLayout(Context context) {
super(context);
init(context);
}
public PreviewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PreviewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
setOrientation(LinearLayout.VERTICAL);
LayoutInflater.from(context).inflate(R.layout.widget_preview_layout, this);
ViewGroup viewGroup = (ViewGroup) getChildAt(0);
mTopPrevious = viewGroup.getChildAt(0);
mTopSelection = (TextView) viewGroup.getChildAt(2);
mTopNext = viewGroup.getChildAt(4);
mSimpleGridLayout = (SimpleGridLayout) getChildAt(1);
viewGroup = (ViewGroup) getChildAt(2);
mBottomPrevious = viewGroup.getChildAt(0);
mBottomSelection = (TextView) viewGroup.getChildAt(2);
mBottomNext = viewGroup.getChildAt(4);
RippleSalon.addRipple(mTopPrevious, false);
RippleSalon.addRipple(mTopSelection, false);
RippleSalon.addRipple(mTopNext, false);
RippleSalon.addRipple(mBottomPrevious, false);
RippleSalon.addRipple(mBottomSelection, false);
RippleSalon.addRipple(mBottomNext, false);
mTopPrevious.setOnClickListener(this);
mTopSelection.setOnClickListener(this);
mTopNext.setOnClickListener(this);
mBottomPrevious.setOnClickListener(this);
mBottomSelection.setOnClickListener(this);
mBottomNext.setOnClickListener(this);
GestureListener gestureListener = new GestureListener();
mGestureDetector = new GestureDetector(context, gestureListener);
mGestureDetector.setIsLongpressEnabled(false);
}
public void setData(PreviewSet[] previewSets, LayoutInflater inflater, Conaco conaco) {
mPreviewSets = previewSets;
mPreviewSetCount = previewSets.length;
mInflater = inflater;
mConaco = conaco;
}
private boolean isLargePreview() {
for (PreviewSet previewSet : mPreviewSets) {
if (previewSet != null) {
return previewSet instanceof LargePreviewSet;
}
}
return false;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
int width = r - l;
if (mWidth != width) {
mWidth = width;
int itemWidth = getResources().getDimensionPixelOffset(
isLargePreview() ? R.dimen.gallery_large_preview_item_width :
R.dimen.gallery_normal_preview_item_width);
int columnCount = Math.round(
(width - getPaddingLeft() - getPaddingRight()) / (float) itemWidth);
columnCount = Math.max(columnCount, 1);
mSimpleGridLayout.setColumnCount(columnCount);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return handleTouchEvent(ev);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
return handleTouchEvent(event);
}
private boolean handleTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
public int getPreviewPageCount() {
return mPreviewSetCount;
}
public void selectPreviewAt(int index) {
if (index < 0 || index >= mPreviewSetCount) {
throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + mPreviewSetCount);
}
mCurrentPreviewIndex = index;
PreviewSet previewSet = mPreviewSets[index];
if (previewSet != null) {
previewSet.bindView(mSimpleGridLayout, mInflater, mConaco);
} else {
// TODO
}
String showText = (index + 1) + "/" + mPreviewSetCount;
mTopSelection.setText(showText);
mBottomSelection.setText(showText);
}
public void tryNextPreview() {
if (mCurrentPreviewIndex < mPreviewSetCount - 1) {
selectPreviewAt(mCurrentPreviewIndex + 1);
}
}
public void tryPreviousPreview() {
if (mCurrentPreviewIndex > 0) {
selectPreviewAt(mCurrentPreviewIndex - 1);
}
}
@Override
public void onClick(View v) {
}
class GestureListener extends GestureDetector.SimpleOnGestureListener {
private boolean mHasScrollX = false;
@Override
public boolean onDown(MotionEvent e) {
mHasScrollX = false;
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
if (Math.abs(distanceX) > Math.abs(distanceY)) {
if (!mHasScrollX) {
mHasScrollX = true;
if (distanceX > 0) {
tryNextPreview();
} else {
tryPreviousPreview();
}
}
return true;
} else {
return false;
}
}
}
}
@@ -36,7 +36,7 @@ import android.widget.FrameLayout;
import android.widget.TextView;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.data.ListUrlBuilder;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.SimpleDialog;
import com.hippo.util.UiUtils;
@@ -0,0 +1,155 @@
package com.hippo.scene;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.os.Build;
import android.support.annotation.NonNull;
import android.view.View;
import android.view.ViewTreeObserver;
import com.hippo.animation.DurationInterpolator;
import com.hippo.animation.SimpleAnimatorListener;
import com.hippo.util.Log;
import com.hippo.util.ViewUtils;
import java.util.HashSet;
import java.util.Set;
public class RippleCurtain extends Curtain {
private static final String TAG = RippleCurtain.class.getSimpleName();
private static long ANIMATE_TIME = 300L;
private int mStartX;
private int mStartY;
private AnimatorSet mAnimatorSet;
public RippleCurtain(int startX, int startY) {
mStartX = startX;
mStartY = startY;
}
@Override
protected void onRebirth() {
mStartX = 0;
mStartY = 0;
}
@Override
public void open(@NonNull final Scene enter, @NonNull final Scene exit) {
final Set<Animator> animatorCollection = new HashSet<>();
final SceneView enterView = enter.getSceneView();
enterView.setStartPoint(mStartX, mStartY);
ViewUtils.setVisibility(enterView, View.INVISIBLE);
// Canvas.clipPath() not work for pre-JELLY_BEAN_MR2 when hardware accelerated
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
ViewUtils.removeHardwareAccelerationSupport(enterView);
}
enterView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewUtils.removeOnGlobalLayoutListener(enterView.getViewTreeObserver(), this);
final View sceneContentView = enter.getSceneView().getChildAt(0);
if (sceneContentView != null) {
sceneContentView.setVisibility(View.INVISIBLE);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(sceneContentView, "alpha", 0f, 1f);
alphaAnim.setDuration(ANIMATE_TIME * 2);
alphaAnim.setInterpolator(new DurationInterpolator(0.3f));
alphaAnim.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
sceneContentView.setVisibility(View.VISIBLE);
}
});
animatorCollection.add(alphaAnim);
} else {
Log.w(TAG, "Can't get enter scene content view");
}
PropertyValuesHolder circlePercentPvh = PropertyValuesHolder.ofFloat("circlePercent", 0f, 1f);
ObjectAnimator animFrame = ObjectAnimator.ofPropertyValuesHolder(enterView, circlePercentPvh);
animFrame.setDuration(ANIMATE_TIME);
animatorCollection.add(animFrame);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(animatorCollection);
mAnimatorSet.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
ViewUtils.setVisibility(enterView, View.VISIBLE);
}
@Override
public void onAnimationEnd(Animator animation) {
dispatchOpenFinished(enter, exit);
hideSceneOnOpen(exit);
mAnimatorSet = null;
// Canvas.clipPath() not work for pre-JELLY_BEAN_MR2 when hardware accelerated
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
ViewUtils.addHardwareAccelerationSupport(enterView);
}
}
});
mAnimatorSet.start();
}
});
}
@Override
public void close(@NonNull final Scene enter, @NonNull final Scene exit) {
showSceneOnClose(enter);
final Set<Animator> animatorCollection = new HashSet<>();
final SceneView exitView = exit.getSceneView();
exitView.setStartPoint(mStartX, mStartY);
// Canvas.clipPath() not work for pre-JELLY_BEAN_MR2 when hardware accelerated
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
ViewUtils.removeHardwareAccelerationSupport(exitView);
}
PropertyValuesHolder circlePercentPvh = PropertyValuesHolder.ofFloat("circlePercent", 1f, 0f);
ObjectAnimator animFrame = ObjectAnimator.ofPropertyValuesHolder(exitView, circlePercentPvh);
animFrame.setDuration(ANIMATE_TIME);
animatorCollection.add(animFrame);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(animatorCollection);
mAnimatorSet.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation, boolean canceled) {
super.onAnimationEnd(animation, canceled);
dispatchCloseFinished(enter, exit);
mAnimatorSet = null;
// Canvas.clipPath() not work for pre-JELLY_BEAN_MR2 when hardware accelerated
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
ViewUtils.addHardwareAccelerationSupport(exitView);
}
}
});
mAnimatorSet.start();
}
@Override
public void endAnimation() {
if (mAnimatorSet != null) {
mAnimatorSet.end();
}
}
@Override
public boolean isInAnimation() {
return mAnimatorSet != null;
}
}
@@ -17,6 +17,8 @@
package com.hippo.scene;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Path;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.MotionEvent;
@@ -27,6 +29,12 @@ public class SceneView extends AbsoluteLayout {
private boolean mEnableTouch = true;
private Path mPath;
private float mRadius;
private float mCirclePercent = 1f;
private float mStartX = -1f;
private float mStartY = -1f;
public SceneView(Context context) {
super(context);
init();
@@ -44,6 +52,7 @@ public class SceneView extends AbsoluteLayout {
private void init() {
setClickable(true);
mPath = new Path();
}
public void setEnableTouch(boolean enableTouch) {
@@ -64,4 +73,65 @@ public class SceneView extends AbsoluteLayout {
public boolean dispatchGenericMotionEvent(@NonNull MotionEvent event) {
return mEnableTouch && super.dispatchGenericMotionEvent(event);
}
private void updateRadius() {
int width = getWidth();
int height = getHeight();
if ((mStartX != -1f || mStartY != -1f) && width != 0 && height != 0) {
float h = Math.max(mStartX, width - mStartX);
float v = Math.max(mStartY, height - mStartY);
mRadius = (float) Math.hypot(h, v);
}
}
@Override
protected void onLayout(boolean changed, int l, int t,
int r, int b) {
super.onLayout(changed, l, t, r, b);
updateRadius();
}
@Override
public void draw(@NonNull Canvas canvas) {
float circlePercent = mCirclePercent;
int saved = 0;
if (circlePercent != 1f && mRadius != 0f) {
mPath.rewind();
mPath.addCircle(mStartX, mStartY, circlePercent * mRadius, Path.Direction.CW);
saved = canvas.save();
canvas.clipPath(mPath);
}
super.draw(canvas);
if (circlePercent != 1f && mRadius != 0f && saved != 0) {
canvas.restoreToCount(saved);
}
}
@SuppressWarnings("unused")
public void setCirclePercent(float circlePercent) {
float largeCirclePercent = Math.max(mCirclePercent, circlePercent);
mCirclePercent = circlePercent;
if (largeCirclePercent == 1f) {
invalidate();
} else {
float radius = mRadius * largeCirclePercent;
invalidate((int) (mStartX - radius), (int) (mStartY - radius),
(int) (mStartX + radius), (int) (mStartY + radius));
}
}
@SuppressWarnings("unused")
public float getCirclePercent() {
return mCirclePercent;
}
public void setStartPoint(float x, float y) {
mStartX = x;
mStartY = y;
updateRadius();
}
}
@@ -157,7 +157,7 @@ public class SimpleDialogCurtain extends Curtain {
final Set<Animator> animatorCollection = new HashSet<>();
// Handle background
int bgColor = enter.getBackgroundColor();
int bgColor = exitDialog.getBackgroundColor();
int endBgColor = bgColor & 0xffffff;
ObjectAnimator colorAnim = ObjectAnimator.ofInt(exit, "backgroundColor", endBgColor);
colorAnim.setEvaluator(ArgbEvaluator.getInstance());
@@ -274,6 +274,16 @@ public final class MathUtils {
return n + 1;
}
/**
*
* @param a
* @param b
* @return
*/
public static int ceilDivide(int a, int b) {
return (a + b - 1) / b;
}
/**
* Return is a and b is in the same side to standard.
* If one of a and b equals standard, return true.
@@ -28,6 +28,8 @@ import android.view.ViewTreeObserver;
public final class ViewUtils {
public static final int MAX_SIZE = Integer.MAX_VALUE & ~(0x3 << 30);
/**
* Get view center location in window
*
@@ -0,0 +1,64 @@
/*
* Copyright 2015 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.widget;
import android.support.annotation.NonNull;
import android.view.View;
import com.hippo.ehviewer.R;
import com.hippo.hotspot.HotspotTouchHelper;
import com.hippo.hotspot.Hotspotable;
public final class AccurateClick {
public static void setOnAccurateClickListener(@NonNull View view, @NonNull OnAccurateClickListener listener) {
AccurateClickHelper accurateClickHelper = new AccurateClickHelper();
view.setTag(R.id.view_tag_accurate_click_helper, accurateClickHelper);
view.setTag(R.id.view_tag_on_accurate_click_listener, listener);
view.setOnTouchListener(new HotspotTouchHelper(accurateClickHelper));
view.setOnClickListener(new DelegateClickListener());
}
static class DelegateClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
Object accurateClickHelper = v.getTag(R.id.view_tag_accurate_click_helper);
Object listener = v.getTag(R.id.view_tag_on_accurate_click_listener);
if (accurateClickHelper instanceof AccurateClickHelper && listener instanceof OnAccurateClickListener) {
AccurateClickHelper ach = (AccurateClickHelper) accurateClickHelper;
((OnAccurateClickListener) listener).onAccurateClick(v, ach.x, ach.y);
}
}
}
static class AccurateClickHelper implements Hotspotable {
public float x;
public float y;
@Override
public void setHotspot(float x, float y) {
this.x = x;
this.y = y;
}
}
public interface OnAccurateClickListener {
void onAccurateClick(View v, float x, float y);
}
}
@@ -43,6 +43,13 @@ public class CardButton extends Button implements CardViewDelegate {
// Empty
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
if (mCardHelper != null) {
mCardHelper.setPadding(left, top, right, bottom);
}
}
@Override
public void setRawPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
@@ -45,7 +45,9 @@ public class CardLinearLayout extends LinearLayout implements CardViewDelegate {
@Override
public void setPadding(int left, int top, int right, int bottom) {
mCardHelper.setPadding(left, top, right, bottom);
if (mCardHelper != null) {
mCardHelper.setPadding(left, top, right, bottom);
}
}
@Override
@@ -0,0 +1,174 @@
/*
* Copyright 2015 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.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.hippo.ehviewer.R;
import com.hippo.util.MathUtils;
import com.hippo.util.ViewUtils;
/**
* not scrollable
*
* @author Hippo
*
*/
public class SimpleGridLayout extends ViewGroup {
private static final int DEFAULT_COLUMN_COUNT = 3;
private int mColumnCount;
private int mItemMargin;
private int[] mRowHeights;
private int mItemWidth;
public SimpleGridLayout(Context context) {
super(context);
init(context, null);
}
public SimpleGridLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public SimpleGridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public void init(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SimpleGridLayout);
mColumnCount = a.getInteger(R.styleable.SimpleGridLayout_columnCount, DEFAULT_COLUMN_COUNT);
mItemMargin = a.getDimensionPixelOffset(R.styleable.SimpleGridLayout_itemMargin, 0);
a.recycle();
}
public void setItemMargin(int itemMargin) {
if (mItemMargin != itemMargin) {
mItemMargin = itemMargin;
requestLayout();
}
}
public void setColumnCount(int columnCount) {
if (columnCount <= 0) {
throw new IllegalStateException("Column count can't be " + columnCount);
}
if (mColumnCount != columnCount) {
mColumnCount = columnCount;
requestLayout();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxRowCount = MathUtils.ceilDivide(getChildCount(), mColumnCount);
if (mRowHeights == null || mRowHeights.length != maxRowCount) {
mRowHeights = new int[maxRowCount];
}
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.UNSPECIFIED) {
maxWidth = 300;
}
if (heightMode == MeasureSpec.UNSPECIFIED) {
maxHeight = ViewUtils.MAX_SIZE;
}
// Get item width MeasureSpec
mItemWidth = Math.max(
(maxWidth - getPaddingLeft() - getPaddingRight() - ((mColumnCount - 1) * mItemMargin)) / mColumnCount, 1);
int itemWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mItemWidth, MeasureSpec.EXACTLY);
int itemHeightMeasureSpec = MeasureSpec.UNSPECIFIED;
int measuredWidth = maxWidth;
int measuredHeight = 0;
int rowHeight = 0;
int row = 0;
int count = getChildCount();
for (int index = 0, indexInRow = 0; index < count; index++, indexInRow++) {
final View child = getChildAt(index);
if (child.getVisibility() == View.GONE) {
indexInRow--;
continue;
}
child.measure(itemWidthMeasureSpec, itemHeightMeasureSpec);
if (indexInRow == mColumnCount) {
// New row
indexInRow = 0;
rowHeight = 0;
row++;
}
rowHeight = Math.max(rowHeight, child.getMeasuredHeight());
if (indexInRow == mColumnCount - 1 || index == count - 1) {
mRowHeights[row] = rowHeight;
measuredHeight += rowHeight + mItemMargin;
}
}
measuredHeight -= mItemMargin;
measuredHeight = Math.min(measuredHeight + getPaddingTop() + getPaddingBottom(), maxHeight);
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int itemWidth = mItemWidth;
int itemMargin = mItemMargin;
int paddingLeft = getPaddingLeft();
int left = paddingLeft;
int top = getPaddingTop();
int row = 0;
int count = getChildCount();
for (int index = 0, indexInRow = 0; index < count; index++, indexInRow++) {
final View child = getChildAt(index);
if (child.getVisibility() == View.GONE) {
indexInRow--;
continue;
}
if (indexInRow == mColumnCount) {
// New row
left = paddingLeft;
top += mRowHeights[row] + itemMargin;
indexInRow = 0;
row++;
}
child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
left += itemWidth + itemMargin;
}
}
}
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:auto="http://schemas.android.com/apk/res-auto"
tools:targetApi="21"
auto:width="24dp"
auto:height="24dp"
auto:viewportWidth="24"
auto:viewportHeight="24"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
auto:pathData="@string/pd_chevron_left"
auto:fillColor="@color/theme_primary"
android:pathData="@string/pd_chevron_left"
android:fillColor="@color/theme_primary"/>
</vector>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:auto="http://schemas.android.com/apk/res-auto"
tools:targetApi="21"
auto:width="24dp"
auto:height="24dp"
auto:viewportWidth="24"
auto:viewportHeight="24"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
auto:pathData="@string/pd_chevron_right"
auto:fillColor="@color/theme_primary"
android:pathData="@string/pd_chevron_right"
android:fillColor="@color/theme_primary"/>
</vector>
@@ -205,43 +205,43 @@
android:orientation="vertical"
android:paddingLeft="32dp"
android:paddingRight="32dp"
android:paddingTop="16dp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:layout_marginLeft="@dimen/keyline_margin"
android:layout_marginRight="@dimen/keyline_margin"
android:background="@color/divider_light"/>
<LinearLayout
android:id="@+id/comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp">
android:paddingBottom="16dp">
<TextView
android:id="@+id/comment_more"
android:id="@+id/no_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
android:textColor="@color/theme_accent"/>
android:textColor="@color/theme_accent"
android:text="@string/no_tags"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:layout_marginLeft="@dimen/keyline_margin"
android:layout_marginRight="@dimen/keyline_margin"
android:background="@color/divider_light"/>
<include
layout="@layout/gallery_detail_comment"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="@dimen/keyline_margin"
android:layout_marginRight="@dimen/keyline_margin"
android:background="@color/divider_light"/>
<com.hippo.ehviewer.widget.PreviewLayout
android:id="@+id/preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"/>
</LinearLayout>
<!-- Header -->
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="@dimen/keyline_margin"
android:paddingRight="@dimen/keyline_margin">
<TextView
android:id="@+id/comment_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingTop="16dp"
android:textColor="@color/theme_accent"/>
</LinearLayout>
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.hippo.ehviewer.widget.LoadImageView
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
auto:aspect="0.667"/>
<TextView
android:id="@+id/index"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
android:layout_marginRight="32dp"
android:orientation="horizontal">
<com.hippo.widget.SimpleImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_chevron_left"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/divider_light"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/text_little_small"
android:textColor="@color/theme_primary"
android:textStyle="bold"/>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/divider_light"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"/>
<com.hippo.widget.SimpleImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_chevron_right"/>
</LinearLayout>
+4 -1
View File
@@ -27,6 +27,9 @@
android:id="@+id/reply"
style="@style/FloatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:layout_gravity="right|bottom"
android:layout_marginRight="@dimen/keyline_margin"
android:layout_marginBottom="16dp"/>
</FrameLayout>
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<merge
xmlns:android="http://schemas.android.com/apk/res/android">
<include
layout="@layout/preview_controller"/>
<com.hippo.widget.SimpleGridLayout
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingLeft="32dp"
android:paddingRight="32dp"
auto:itemMargin="8dp"/>
<include
layout="@layout/preview_controller"/>
</merge>
@@ -60,6 +60,30 @@
<string name="go_to_error_not_number">请输入数字</string>
<string name="go_to_error_invaild">当前页面无效</string>
<!-- Detail -->
<string name="page_count">%d 页</string>
<string name="favorited_times">%d \u2665</string>
<string name="more_information">更多信息</string>
<string name="we_feel">大家感觉 %s</string>
<string name="no_comments">暂无评论</string>
<string name="no_more_comments">暂无更多评论</string>
<string name="more_comment">更多评论</string>
<!-- Rating -->
<string name="rating10">根本把持不住</string>
<string name="rating9">好极了</string>
<string name="rating8">很棒</string>
<string name="rating7">不错</string>
<string name="rating6">还行</string>
<string name="rating5">一般般</string>
<string name="rating4">不行</string>
<string name="rating3">糟糕</string>
<string name="rating2">瞎眼</string>
<string name="rating1">快要窒息了</string>
<string name="rating0">…</string>
<string name="em_cant_find_activity">无法找到指定 Activity</string>
<!-- Error message -->
<string name="em_timeout">超时</string>
<string name="em_unknown_host">找不到主机</string>
@@ -101,4 +125,10 @@
<string name="username">用户名</string>
<string name="password">密码</string>
<string name="read">阅读</string>
<string name="torrent">种子</string>
<string name="share">分享</string>
<string name="comments">评论</string>
</resources>
+5
View File
@@ -71,4 +71,9 @@
</attr>
</declare-styleable>
<declare-styleable name="SimpleGridLayout">
<attr name="columnCount" format="integer"/>
<attr name="itemMargin" format="dimension"/>
</declare-styleable>
</resources>
+3
View File
@@ -130,6 +130,9 @@
<dimen name="add_size">20dp</dimen>
<dimen name="add_thickness">2dp</dimen>
<dimen name="gallery_normal_preview_item_width">96dp</dimen>
<dimen name="gallery_large_preview_item_width">128dp</dimen>
<!-- Text size -->
<dimen name="text_super_large">24sp</dimen>
<dimen name="text_large">22sp</dimen>
+22
View File
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 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.
-->
<resources>
<item type="id" name="view_tag_accurate_click_helper"/>
<item type="id" name="view_tag_on_accurate_click_listener"/>
</resources>
+2
View File
@@ -38,5 +38,7 @@
<string name="pd_water_pump" translatable="false">M19,14.5C19,14.5 21,16.67 21,18A2,2 0 0,1 19,20A2,2 0 0,1 17,18C17,16.67 19,14.5 19,14.5M5,18V9A2,2 0 0,1 3,7A2,2 0 0,1 5,5V4A2,2 0 0,1 7,2H9A2,2 0 0,1 11,4V5H19A2,2 0 0,1 21,7V9L21,11A1,1 0 0,1 22,12A1,1 0 0,1 21,13H17A1,1 0 0,1 16,12A1,1 0 0,1 17,11V9H11V18H12A2,2 0 0,1 14,20V22H2V20A2,2 0 0,1 4,18H5Z</string>
<string name="pd_share" translatable="false">M18,16.08C17.24,16.08 16.56,16.38 16.04,16.85L8.91,12.7C8.96,12.47 9,12.24 9,12C9,11.76 8.96,11.53 8.91,11.3L15.96,7.19C16.5,7.69 17.21,8 18,8A3,3 0 0,0 21,5A3,3 0 0,0 18,2A3,3 0 0,0 15,5C15,5.24 15.04,5.47 15.09,5.7L8.04,9.81C7.5,9.31 6.79,9 6,9A3,3 0 0,0 3,12A3,3 0 0,0 6,15C6.79,15 7.5,14.69 8.04,14.19L15.16,18.34C15.11,18.55 15.08,18.77 15.08,19C15.08,20.61 16.39,21.91 18,21.91C19.61,21.91 20.92,20.61 20.92,19A2.92,2.92 0 0,0 18,16.08Z</string>
<string name="pd_thumbs_up_down" translatable="false">M22.5,10.5H15.75C15.13,10.5 14.6,10.88 14.37,11.41L12.11,16.7C12.04,16.87 12,17.06 12,17.25V18.5A1,1 0 0,0 13,19.5H18.18L17.5,22.68V22.92C17.5,23.23 17.63,23.5 17.83,23.72L18.62,24.5L23.56,19.56C23.83,19.29 24,18.91 24,18.5V12A1.5,1.5 0 0,0 22.5,10.5M12,6.5A1,1 0 0,0 11,5.5H5.82L6.5,2.32V2.09C6.5,1.78 6.37,1.5 6.17,1.29L5.38,0.5L0.44,5.44C0.17,5.71 0,6.09 0,6.5V13A1.5,1.5 0 0,0 1.5,14.5H8.25C8.87,14.5 9.4,14.12 9.63,13.59L11.89,8.3C11.96,8.13 12,7.94 12,7.75V6.5Z</string>
<string name="pd_chevron_left" translatable="false">M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z</string>
<string name="pd_chevron_right" translatable="false">M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z</string>
</resources>
+4
View File
@@ -82,6 +82,10 @@
<string name="favorited_times">%d \u2665</string>
<string name="more_information">More information</string>
<string name="we_feel">It is %s</string>
<string name="no_tags">No tags</string>
<string name="no_comments">No comments</string>
<string name="no_more_comments">No more comments</string>
<string name="more_comment">More comments</string>
<!-- Rating -->
<string name="rating10">a MASTERPIECE</string>
+1 -1
Submodule hotspot updated: 1c2b4d6160...0cddb7f7ca.