Fixed commentview events, long press and click now work as expected.

captchafix
Florens Douwes 11 years ago
parent 93fb5a7327
commit 65d09ba0fb
  1. 39
      Chan/src/org/floens/chan/adapter/PostAdapter.java
  2. 20
      Chan/src/org/floens/chan/loader/LoaderPool.java
  3. 179
      Chan/src/org/floens/chan/model/Post.java
  4. 22
      Chan/src/org/floens/chan/utils/Utils.java
  5. 269
      Chan/src/org/floens/chan/view/PostView.java

@ -27,9 +27,9 @@ public class PostAdapter extends BaseAdapter {
private boolean endOfLine; private boolean endOfLine;
private int count = 0; private int count = 0;
private final List<Post> postList = new ArrayList<Post>(); private final List<Post> postList = new ArrayList<Post>();
public PostAdapter(Context activity, ThreadManager threadManager, ListView listView) { public PostAdapter(Context activity, ThreadManager threadManager, ListView listView) {
this.context = activity; context = activity;
this.threadManager = threadManager; this.threadManager = threadManager;
this.listView = listView; this.listView = listView;
} }
@ -52,33 +52,33 @@ public class PostAdapter extends BaseAdapter {
public long getItemId(int position) { public long getItemId(int position) {
return position; return position;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
if (position >= getCount() - 1 && !endOfLine && threadManager.getLoadable().isBoardMode()) { if (position >= getCount() - 1 && !endOfLine && threadManager.getLoadable().isBoardMode()) {
// Try to load more posts // Try to load more posts
threadManager.requestNextData(); threadManager.requestNextData();
} }
if (position >= count) { if (position >= count) {
return createThreadEndView(); return createThreadEndView();
} else { } else {
PostView postView = null; PostView postView = null;
if (position >= 0 && position < postList.size()) { if (position >= 0 && position < postList.size()) {
if (convertView != null && convertView instanceof PostView) { if (convertView != null && convertView instanceof PostView) {
postView = (PostView) convertView; postView = (PostView) convertView;
} else { } else {
postView = new PostView(context); postView = new PostView(context);
} }
postView.setPost(postList.get(position), threadManager); postView.setPost(postList.get(position), threadManager);
} }
return postView; return postView;
} }
} }
private View createThreadEndView() { private View createThreadEndView() {
if (threadManager.getLoadable().isThreadMode()) { if (threadManager.getLoadable().isThreadMode()) {
ThreadWatchCounterView view = new ThreadWatchCounterView(context); ThreadWatchCounterView view = new ThreadWatchCounterView(context);
@ -102,37 +102,38 @@ public class PostAdapter extends BaseAdapter {
} }
} }
} }
public void addList(List<Post> list) { public void addList(List<Post> list) {
postList.addAll(list); postList.addAll(list);
count = postList.size(); count = postList.size();
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void setList(List<Post> list) { public void setList(List<Post> list) {
postList.clear(); postList.clear();
postList.addAll(list); postList.addAll(list);
count = postList.size(); count = postList.size();
notifyDataSetChanged(); notifyDataSetChanged();
} }
public List<Post> getList() { public List<Post> getList() {
return postList; return postList;
} }
public void setEndOfLine(boolean endOfLine) { public void setEndOfLine(boolean endOfLine) {
this.endOfLine = endOfLine; this.endOfLine = endOfLine;
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void scrollToPost(Post post) { public void scrollToPost(Post post) {
for (int i = 0; i < postList.size(); i++) { for (int i = 0; i < postList.size(); i++) {
if (postList.get(i).no == post.no) { if (postList.get(i).no == post.no) {
listView.smoothScrollToPosition(i); // listView.smoothScrollToPosition(i); does not work when a view is taller than the container
listView.setSelection(i);
break; break;
} }
} }

@ -6,37 +6,37 @@ import java.util.Map;
import org.floens.chan.model.Loadable; import org.floens.chan.model.Loadable;
public class LoaderPool { public class LoaderPool {
private static final String TAG = "LoaderPool"; // private static final String TAG = "LoaderPool";
private static LoaderPool instance; private static LoaderPool instance;
private static Map<Loadable, Loader> loaders = new HashMap<Loadable, Loader>(); private static Map<Loadable, Loader> loaders = new HashMap<Loadable, Loader>();
public static LoaderPool getInstance() { public static LoaderPool getInstance() {
if (instance == null) { if (instance == null) {
instance = new LoaderPool(); instance = new LoaderPool();
} }
return instance; return instance;
} }
public Loader obtain(Loadable loadable, Loader.LoaderListener listener) { public Loader obtain(Loadable loadable, Loader.LoaderListener listener) {
Loader loader = loaders.get(loadable); Loader loader = loaders.get(loadable);
if (loader == null) { if (loader == null) {
loader = new Loader(loadable); loader = new Loader(loadable);
loaders.put(loadable, loader); loaders.put(loadable, loader);
} }
loader.addListener(listener); loader.addListener(listener);
return loader; return loader;
} }
public void release(Loader loader, Loader.LoaderListener listener) { public void release(Loader loader, Loader.LoaderListener listener) {
if (!loaders.containsValue(loader)) { if (!loaders.containsValue(loader)) {
throw new RuntimeException("The released loader does not exist"); throw new RuntimeException("The released loader does not exist");
} }
if (loader.removeListener(listener)) { if (loader.removeListener(listener)) {
loaders.remove(loader.getLoadable()); loaders.remove(loader.getLoadable());
} }

@ -17,10 +17,12 @@ import org.jsoup.parser.Parser;
import android.graphics.Color; import android.graphics.Color;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
/** /**
* Contains all data needer to represent a single post. * Contains all data needed to represent a single post.
*/ */
public class Post { public class Post {
public String board; public String board;
@ -50,121 +52,174 @@ public class Post {
public long time = 0; public long time = 0;
public String email = ""; public String email = "";
public boolean isSavedReply = false; public boolean isSavedReply = false;
/** /**
* This post replies to the these ids * This post replies to the these ids
*/ */
public List<Integer> repliesTo = new ArrayList<Integer>(); public List<Integer> repliesTo = new ArrayList<Integer>();
/** /**
* These ids replied to this post * These ids replied to this post
*/ */
public List<Integer> repliesFrom = new ArrayList<Integer>(); public List<Integer> repliesFrom = new ArrayList<Integer>();
public final ArrayList<PostLinkable> linkables = new ArrayList<PostLinkable>(); public final ArrayList<PostLinkable> linkables = new ArrayList<PostLinkable>();
/** /**
* The PostView the Post is currently bound to. * The PostView the Post is currently bound to.
*/ */
public SpannableString subjectSpan;
public SpannableString nameSpan;
public SpannableString tripcodeSpan;
public SpannableString idSpan;
public SpannableString capcodeSpan;
private PostView linkableListener; private PostView linkableListener;
private String rawComment; private String rawComment;
public Post() { public Post() {
} }
public void setComment(String e) { public void setComment(String e) {
rawComment = e; rawComment = e;
} }
public void setLinkableListener(PostView listener) { public void setLinkableListener(PostView listener) {
linkableListener = listener; linkableListener = listener;
} }
public PostView getLinkableListener() { public PostView getLinkableListener() {
return linkableListener; return linkableListener;
} }
/** /**
* Finish up the data * Finish up the data
*
* @return false if this data is invalid * @return false if this data is invalid
*/ */
public boolean finish(Loadable loadable) { public boolean finish(Loadable loadable) {
if (board == null) return false; if (board == null)
return false;
if (no < 0 || resto < 0 || date == null) return false;
if (no < 0 || resto < 0 || date == null)
return false;
isOP = resto == 0; isOP = resto == 0;
if (isOP && replies < 0) return false; if (isOP && replies < 0)
return false;
if (ext != null) hasImage = true;
if (ext != null) {
hasImage = true;
}
if (hasImage) { if (hasImage) {
if (filename == null || tim == null || ext == null || imageWidth <= 0 || imageHeight <= 0) return false; if (filename == null || tim == null || ext == null || imageWidth <= 0 || imageHeight <= 0)
return false;
thumbnailUrl = ChanUrls.getThumbnailUrl(board, tim); thumbnailUrl = ChanUrls.getThumbnailUrl(board, tim);
imageUrl = ChanUrls.getImageUrl(board, tim, ext); imageUrl = ChanUrls.getImageUrl(board, tim, ext);
} }
if (rawComment != null) { if (rawComment != null) {
comment = parseComment(rawComment, loadable.simpleMode); comment = parseComment(rawComment, loadable.simpleMode);
} }
try { try {
if (!TextUtils.isEmpty(name)) { if (!TextUtils.isEmpty(name)) {
name = Parser.unescapeEntities(name, false); name = Parser.unescapeEntities(name, false);
} }
if (!TextUtils.isEmpty(subject)) { if (!TextUtils.isEmpty(subject)) {
subject = Parser.unescapeEntities(subject, false); subject = Parser.unescapeEntities(subject, false);
} }
} catch(Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
parseSpans();
return true; return true;
} }
private void parseSpans() {
if (!TextUtils.isEmpty(subject)) {
subjectSpan = new SpannableString(subject);
subjectSpan.setSpan(new ForegroundColorSpan(Color.argb(255, 15, 12, 93)), 0, subjectSpan.length(), 0);
}
if (!TextUtils.isEmpty(name)) {
nameSpan = new SpannableString(name);
nameSpan.setSpan(new ForegroundColorSpan(Color.argb(255, 17, 119, 67)), 0, nameSpan.length(), 0);
}
if (!TextUtils.isEmpty(tripcode)) {
tripcodeSpan = new SpannableString(tripcode);
tripcodeSpan.setSpan(new ForegroundColorSpan(Color.argb(255, 17, 119, 67)), 0, tripcodeSpan.length(), 0);
tripcodeSpan.setSpan(new AbsoluteSizeSpan(10, true), 0, tripcodeSpan.length(), 0);
}
if (!TextUtils.isEmpty(id)) {
idSpan = new SpannableString(" ID: " + id + " ");
// Stolen from the 4chan extension
int hash = id.hashCode();
int r = (hash >> 24) & 0xff;
int g = (hash >> 16) & 0xff;
int b = (hash >> 8) & 0xff;
int idColor = (0xff << 24) + (r << 16) + (g << 8) + b;
int idBgColor = ((r * 0.299f) + (g * 0.587f) + (b * 0.114f)) > 125f ? 0xff636363 : 0x00000000;
idSpan.setSpan(new ForegroundColorSpan(idColor), 0, idSpan.length(), 0);
idSpan.setSpan(new BackgroundColorSpan(idBgColor), 0, idSpan.length(), 0);
idSpan.setSpan(new AbsoluteSizeSpan(10, true), 0, idSpan.length(), 0);
}
if (!TextUtils.isEmpty(capcode)) {
capcodeSpan = new SpannableString("Capcode: " + capcode);
capcodeSpan.setSpan(new ForegroundColorSpan(Color.argb(255, 255, 0, 0)), 0, capcodeSpan.length(), 0);
capcodeSpan.setSpan(new AbsoluteSizeSpan(10, true), 0, capcodeSpan.length(), 0);
}
}
private CharSequence parseComment(String commentRaw, boolean simpleMode) { private CharSequence parseComment(String commentRaw, boolean simpleMode) {
if (simpleMode) { if (simpleMode)
return ""; return "";
}
CharSequence total = new SpannableString(""); CharSequence total = new SpannableString("");
try { try {
String comment = commentRaw.replace("<wbr>", ""); String comment = commentRaw.replace("<wbr>", "");
Document document = Jsoup.parseBodyFragment(comment); Document document = Jsoup.parseBodyFragment(comment);
List<Node> nodes = document.body().childNodes(); List<Node> nodes = document.body().childNodes();
for (Node node : nodes) { for (Node node : nodes) {
String nodeName = node.nodeName(); String nodeName = node.nodeName();
if (node instanceof TextNode) { if (node instanceof TextNode) {
String text = ((TextNode)node).text(); String text = ((TextNode) node).text();
// Find url's in the text node // Find url's in the text node
if (text.contains("://")) { if (text.contains("://")) {
String[] parts = text.split("\\s"); String[] parts = text.split("\\s");
for (String item : parts) { for (String item : parts) {
if (item.contains("://")) { if (item.contains("://")) {
try { try {
URL url = new URL(item); URL url = new URL(item);
SpannableString link = new SpannableString(url.toString()); SpannableString link = new SpannableString(url.toString());
// link.setSpan(new ForegroundColorSpan(Color.argb(255, 0, 0, 180)), 0, link.length(), 0);
PostLinkable pl = new PostLinkable(this, item, item, PostLinkable.Type.LINK);
// linkables.add(new PostLinkable(this, item, item, PostLinkable.Type.LINK));
PostLinkable pl = new PostLinkable(this, item, item, PostLinkable.Type.LINK);
link.setSpan(pl, 0, link.length(), 0); link.setSpan(pl, 0, link.length(), 0);
linkables.add(pl); linkables.add(pl);
total = TextUtils.concat(total, link, " "); total = TextUtils.concat(total, link, " ");
} catch(Exception e) { } catch (Exception e) {
total = TextUtils.concat(total, item, " "); total = TextUtils.concat(total, item, " ");
} }
} }
@ -174,23 +229,23 @@ public class Post {
} }
} else if (nodeName.equals("br")) { } else if (nodeName.equals("br")) {
total = TextUtils.concat(total, "\n"); total = TextUtils.concat(total, "\n");
} else if (nodeName.equals("span")){ } else if (nodeName.equals("span")) {
Element span = (Element)node; Element span = (Element) node;
SpannableString quote = new SpannableString(span.text()); SpannableString quote = new SpannableString(span.text());
quote.setSpan(new ForegroundColorSpan(Color.argb(255, 120, 153, 34)), 0, quote.length(), 0); quote.setSpan(new ForegroundColorSpan(Color.argb(255, 120, 153, 34)), 0, quote.length(), 0);
total = TextUtils.concat(total, quote); total = TextUtils.concat(total, quote);
} else if (nodeName.equals("a")) { } else if (nodeName.equals("a")) {
Element anchor = (Element)node; Element anchor = (Element) node;
SpannableString link = new SpannableString(anchor.text()); SpannableString link = new SpannableString(anchor.text());
Type t = anchor.text().contains("://") ? Type.LINK : Type.QUOTE; Type t = anchor.text().contains("://") ? Type.LINK : Type.QUOTE;
PostLinkable pl = new PostLinkable(this, anchor.text(), anchor.attr("href"), t); PostLinkable pl = new PostLinkable(this, anchor.text(), anchor.attr("href"), t);
link.setSpan(pl, 0, link.length(), 0); link.setSpan(pl, 0, link.length(), 0);
linkables.add(pl); linkables.add(pl);
if (t == Type.QUOTE) { if (t == Type.QUOTE) {
try { try {
// Get post id // Get post id
@ -199,26 +254,22 @@ public class Post {
int id = Integer.parseInt(splitted[1]); int id = Integer.parseInt(splitted[1]);
repliesTo.add(id); repliesTo.add(id);
} }
} catch(NumberFormatException e) {} } catch (NumberFormatException e) {
}
} }
total = TextUtils.concat(total, link); total = TextUtils.concat(total, link);
} else { } else {
// Unknown tag, add the inner part // Unknown tag, add the inner part
if (node instanceof Element) { if (node instanceof Element) {
total = TextUtils.concat(total, ((Element)node).text()); total = TextUtils.concat(total, ((Element) node).text());
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return total; return total;
} }
} }

@ -1,5 +1,6 @@
package org.floens.chan.utils; package org.floens.chan.utils;
import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
@ -13,19 +14,24 @@ public class Utils {
*/ */
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void setPressedDrawable(View view) { public static void setPressedDrawable(View view) {
TypedArray arr = view.getContext().obtainStyledAttributes( Drawable drawable = Utils.getSelectableBackgroundDrawable(view.getContext());
view.setBackgroundDrawable(drawable);
}
public static Drawable getSelectableBackgroundDrawable(Context context) {
TypedArray arr = context.obtainStyledAttributes(
new int[] {android.R.attr.selectableItemBackground}); new int[] {android.R.attr.selectableItemBackground});
Drawable drawable = arr.getDrawable(0); Drawable drawable = arr.getDrawable(0);
view.setBackgroundDrawable(drawable);
arr.recycle(); arr.recycle();
return drawable;
} }
/** /**
* Causes the runnable to be added to the message queue. * Causes the runnable to be added to the message queue.
* The runnable will be run on the ui thread. * The runnable will be run on the ui thread.
* @param runnable * @param runnable
*/ */
public static void runOnUiThread(Runnable runnable) { public static void runOnUiThread(Runnable runnable) {

@ -13,14 +13,18 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.text.style.AbsoluteSizeSpan; import android.text.style.AbsoluteSizeSpan;
import android.text.style.BackgroundColorSpan; import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan; import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -33,14 +37,15 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
private final static LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); private final static LinearLayout.LayoutParams wrapParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
private final static LinearLayout.LayoutParams matchWrapParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); private final static LinearLayout.LayoutParams matchWrapParams = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
private final static LinearLayout.LayoutParams wrapMatchParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); private final static LinearLayout.LayoutParams wrapMatchParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
private final Activity context; private final Activity context;
private ThreadManager manager; private ThreadManager manager;
private Post post; private Post post;
private boolean isBuild = false; private boolean isBuild = false;
private LinearLayout full; private LinearLayout full;
private LinearLayout right;
private NetworkImageView imageView; private NetworkImageView imageView;
private TextView titleView; private TextView titleView;
private TextView commentView; private TextView commentView;
@ -48,7 +53,7 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
private LinearLayout iconView; private LinearLayout iconView;
private ImageView stickyView; private ImageView stickyView;
private NetworkImageView countryView; private NetworkImageView countryView;
/** /**
* Represents a post. * Represents a post.
* Use setPost(Post ThreadManager) to fill it with data. * Use setPost(Post ThreadManager) to fill it with data.
@ -58,36 +63,33 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
public PostView(Context activity) { public PostView(Context activity) {
super(activity); super(activity);
context = (Activity) activity; context = (Activity) activity;
init();
} }
public PostView(Context activity, AttributeSet attbs) { public PostView(Context activity, AttributeSet attbs) {
super(activity, attbs); super(activity, attbs);
context = (Activity) activity; context = (Activity) activity;
init();
} }
public PostView(Context activity, AttributeSet attbs, int style) { public PostView(Context activity, AttributeSet attbs, int style) {
super(activity, attbs, style); super(activity, attbs, style);
context = (Activity) activity; context = (Activity) activity;
init();
} }
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
if (post != null) { if (post != null) {
post.setLinkableListener(null); post.setLinkableListener(null);
} }
} }
public void setPost(final Post post, final ThreadManager manager) { public void setPost(final Post post, final ThreadManager manager) {
this.post = post; this.post = post;
this.manager = manager; this.manager = manager;
buildView(context); buildView(context);
if (post.hasImage) { if (post.hasImage) {
imageView.setVisibility(View.VISIBLE); imageView.setVisibility(View.VISIBLE);
imageView.setImageUrl(post.thumbnailUrl, ChanApplication.getImageLoader()); imageView.setImageUrl(post.thumbnailUrl, ChanApplication.getImageLoader());
@ -95,76 +97,50 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
imageView.setVisibility(View.GONE); imageView.setVisibility(View.GONE);
imageView.setImageUrl(null, null); imageView.setImageUrl(null, null);
} }
CharSequence total = new SpannableString(""); CharSequence total = new SpannableString("");
if (!TextUtils.isEmpty(post.subject)) { if (post.subjectSpan != null) {
SpannableString subject = new SpannableString(post.subject); total = TextUtils.concat(total, post.subjectSpan, "\n");
subject.setSpan(new ForegroundColorSpan(Color.argb(255, 15, 12, 93)), 0, subject.length(), 0);
total = TextUtils.concat(total, subject, "\n");
} }
if (!TextUtils.isEmpty(post.name)) { if (post.nameSpan != null) {
SpannableString name = new SpannableString(post.name); total = TextUtils.concat(total, post.nameSpan, " ");
name.setSpan(new ForegroundColorSpan(Color.argb(255, 17, 119, 67)), 0, name.length(), 0);
total = TextUtils.concat(total, name, " ");
} }
if (!TextUtils.isEmpty(post.tripcode)) { if (post.tripcodeSpan != null) {
SpannableString tripcode = new SpannableString(post.tripcode); total = TextUtils.concat(total, post.tripcodeSpan, " ");
tripcode.setSpan(new ForegroundColorSpan(Color.argb(255, 17, 119, 67)), 0, tripcode.length(), 0);
tripcode.setSpan(new AbsoluteSizeSpan(10, true), 0, tripcode.length(), 0);
total = TextUtils.concat(total, tripcode, " ");
} }
if (!TextUtils.isEmpty(post.id)) { if (post.idSpan != null) {
SpannableString id = new SpannableString(" ID: " + post.id + " "); total = TextUtils.concat(total, post.idSpan, " ");
IDColor c = computeIDColor(post.id);
id.setSpan(new ForegroundColorSpan(c.color), 0, id.length(), 0);
id.setSpan(new BackgroundColorSpan(c.backgroundColor), 0, id.length(), 0);
id.setSpan(new AbsoluteSizeSpan(10, true), 0, id.length(), 0);
total = TextUtils.concat(total, id, " ");
} }
if (!TextUtils.isEmpty(post.capcode)) { if (post.capcodeSpan != null) {
SpannableString tripcode = new SpannableString("Capcode: " + post.capcode); total = TextUtils.concat(total, post.capcodeSpan, " ");
tripcode.setSpan(new ForegroundColorSpan(Color.argb(255, 255, 0, 0)), 0, tripcode.length(), 0);
tripcode.setSpan(new AbsoluteSizeSpan(10, true), 0, tripcode.length(), 0);
total = TextUtils.concat(total, tripcode, " ");
} }
CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(post.time * 1000L, System.currentTimeMillis(), CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(post.time * 1000L, System.currentTimeMillis(),
DateUtils.SECOND_IN_MILLIS, 0); DateUtils.SECOND_IN_MILLIS, 0);
SpannableString date = new SpannableString("No." + post.no + " " + relativeTime); SpannableString date = new SpannableString("No." + post.no + " " + relativeTime);
date.setSpan(new ForegroundColorSpan(Color.argb(255, 100, 100, 100)), 0, date.length(), 0); date.setSpan(new ForegroundColorSpan(Color.argb(255, 100, 100, 100)), 0, date.length(), 0);
date.setSpan(new AbsoluteSizeSpan(10, true), 0, date.length(), 0); date.setSpan(new AbsoluteSizeSpan(10, true), 0, date.length(), 0);
total = TextUtils.concat(total, date, " "); total = TextUtils.concat(total, date, " ");
titleView.setText(total); titleView.setText(total);
if (!TextUtils.isEmpty(post.comment)) { if (!TextUtils.isEmpty(post.comment)) {
commentView.setVisibility(View.VISIBLE); commentView.setVisibility(View.VISIBLE);
commentView.setText(post.comment); commentView.setText(post.comment);
commentView.setMovementMethod(LinkMovementMethod.getInstance()); commentView.setMovementMethod(new PostViewMovementMethod());
commentView.setOnClickListener(new OnClickListener() { commentView.setOnClickListener(this);
@Override commentView.setOnLongClickListener(this);
public void onClick(View v) {
PostView.this.onClick(v);
}
});
commentView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return PostView.this.onLongClick(v);
}
});
if (manager.getLoadable().isThreadMode()) { if (manager.getLoadable().isThreadMode()) {
post.setLinkableListener(this); post.setLinkableListener(this);
} }
if (manager.getLoadable().isBoardMode()) { if (manager.getLoadable().isBoardMode()) {
int maxHeight = context.getResources().getDimensionPixelSize(R.dimen.post_max_height); int maxHeight = context.getResources().getDimensionPixelSize(R.dimen.post_max_height);
commentView.setMaxHeight(maxHeight); commentView.setMaxHeight(maxHeight);
@ -178,20 +154,20 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
commentView.setOnLongClickListener(null); commentView.setOnLongClickListener(null);
post.setLinkableListener(null); post.setLinkableListener(null);
} }
if ((post.isOP && manager.getLoadable().isBoardMode() && post.replies > 0) || (post.repliesFrom.size() > 0)) { if ((post.isOP && manager.getLoadable().isBoardMode() && post.replies > 0) || (post.repliesFrom.size() > 0)) {
repliesCountView.setVisibility(View.VISIBLE); repliesCountView.setVisibility(View.VISIBLE);
String text = ""; String text = "";
int count = manager.getLoadable().isBoardMode() ? post.replies : post.repliesFrom.size(); int count = manager.getLoadable().isBoardMode() ? post.replies : post.repliesFrom.size();
if (count > 1) { if (count > 1) {
text = count + " " + context.getString(R.string.multiple_replies); text = count + " " + context.getString(R.string.multiple_replies);
} else if (count == 1) { } else if (count == 1) {
text = count + " " + context.getString(R.string.one_reply); text = count + " " + context.getString(R.string.one_reply);
} }
if (manager.getLoadable().isThreadMode()) { if (manager.getLoadable().isThreadMode()) {
repliesCountView.setOnClickListener(new View.OnClickListener() { repliesCountView.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -200,18 +176,18 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
} }
}); });
} }
repliesCountView.setText(text); repliesCountView.setText(text);
} else { } else {
repliesCountView.setVisibility(View.GONE); repliesCountView.setVisibility(View.GONE);
repliesCountView.setOnClickListener(null); repliesCountView.setOnClickListener(null);
} }
boolean showCountryFlag = !TextUtils.isEmpty(post.country); boolean showCountryFlag = !TextUtils.isEmpty(post.country);
boolean showStickyIcon = post.sticky; boolean showStickyIcon = post.sticky;
iconView.setVisibility((showCountryFlag || showStickyIcon) ? View.VISIBLE : View.GONE); iconView.setVisibility((showCountryFlag || showStickyIcon) ? View.VISIBLE : View.GONE);
stickyView.setVisibility(showStickyIcon ? View.VISIBLE : View.GONE); stickyView.setVisibility(showStickyIcon ? View.VISIBLE : View.GONE);
if (showCountryFlag) { if (showCountryFlag) {
countryView.setVisibility(View.VISIBLE); countryView.setVisibility(View.VISIBLE);
@ -220,31 +196,22 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
countryView.setVisibility(View.GONE); countryView.setVisibility(View.GONE);
countryView.setImageUrl(null, null); countryView.setImageUrl(null, null);
} }
if (post.isOP && manager.getLoadable().isBoardMode()) {
full.setClickable(true);
full.setFocusable(true);
full.setOnClickListener(this);
Utils.setPressedDrawable(full);
}
if (post.isSavedReply) { if (post.isSavedReply) {
full.setBackgroundColor(0xFFD6BAD0); full.setBackgroundColor(0xFFD6BAD0);
} else { } else {
full.setBackgroundColor(0x00000000); full.setBackgroundColor(0x00000000);
} }
if (manager.getLoadable().isBoardMode()) {
Utils.setPressedDrawable(right);
}
} }
private void init() {
setOnClickListener(this);
setOnLongClickListener(this);
}
private void buildView(final Context context) { private void buildView(final Context context) {
if (isBuild) return; if (isBuild) return;
isBuild = true; isBuild = true;
Resources resources = context.getResources(); Resources resources = context.getResources();
int postPadding = resources.getDimensionPixelSize(R.dimen.post_padding); int postPadding = resources.getDimensionPixelSize(R.dimen.post_padding);
int commentPadding = resources.getDimensionPixelSize(R.dimen.post_comment_padding); int commentPadding = resources.getDimensionPixelSize(R.dimen.post_comment_padding);
@ -252,99 +219,88 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
int iconWidth = resources.getDimensionPixelSize(R.dimen.post_icon_width); int iconWidth = resources.getDimensionPixelSize(R.dimen.post_icon_width);
int iconHeight = resources.getDimensionPixelSize(R.dimen.post_icon_height); int iconHeight = resources.getDimensionPixelSize(R.dimen.post_icon_height);
int imageSize = resources.getDimensionPixelSize(R.dimen.thumbnail_size); int imageSize = resources.getDimensionPixelSize(R.dimen.thumbnail_size);
full = new LinearLayout(context); full = new LinearLayout(context);
full.setLayoutParams(matchParams); full.setLayoutParams(matchParams);
full.setOrientation(HORIZONTAL); full.setOrientation(HORIZONTAL);
// Create thumbnail // Create thumbnail
imageView = new NetworkImageView(context); imageView = new NetworkImageView(context);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setFadeIn(100); imageView.setFadeIn(100);
imageView.setOnClickListener(new View.OnClickListener() { imageView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
manager.onThumbnailClicked(post); manager.onThumbnailClicked(post);
} }
}); });
LinearLayout left = new LinearLayout(context); LinearLayout left = new LinearLayout(context);
left.setOrientation(VERTICAL); left.setOrientation(VERTICAL);
left.setBackgroundColor(0xffdddddd); left.setBackgroundColor(0xffdddddd);
left.addView(imageView, new LinearLayout.LayoutParams(imageSize, imageSize)); left.addView(imageView, new LinearLayout.LayoutParams(imageSize, imageSize));
full.addView(left, wrapMatchParams); full.addView(left, wrapMatchParams);
full.setMinimumHeight(imageSize); full.setMinimumHeight(imageSize);
LinearLayout right = new LinearLayout(context); right = new LinearLayout(context);
right.setOrientation(VERTICAL); right.setOrientation(VERTICAL);
LinearLayout header = new LinearLayout(context); LinearLayout header = new LinearLayout(context);
header.setOrientation(HORIZONTAL); header.setOrientation(HORIZONTAL);
titleView = new TextView(context); titleView = new TextView(context);
titleView.setTextSize(14); titleView.setTextSize(14);
titleView.setPadding(postPadding, postPadding, postPadding, 0); titleView.setPadding(postPadding, postPadding, postPadding, 0);
header.addView(titleView, wrapParams); header.addView(titleView, wrapParams);
right.addView(header, matchWrapParams); right.addView(header, matchWrapParams);
iconView = new LinearLayout(context); iconView = new LinearLayout(context);
iconView.setOrientation(HORIZONTAL); iconView.setOrientation(HORIZONTAL);
iconView.setPadding(postPadding, iconPadding, postPadding, 0); iconView.setPadding(postPadding, iconPadding, postPadding, 0);
stickyView = new ImageView(context); stickyView = new ImageView(context);
stickyView.setImageBitmap(IconCache.stickyIcon); stickyView.setImageBitmap(IconCache.stickyIcon);
iconView.addView(stickyView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); iconView.addView(stickyView, new LinearLayout.LayoutParams(iconWidth, iconHeight));
countryView = new NetworkImageView(context); countryView = new NetworkImageView(context);
countryView.setScaleType(ImageView.ScaleType.FIT_CENTER); countryView.setScaleType(ImageView.ScaleType.FIT_CENTER);
iconView.addView(countryView, new LinearLayout.LayoutParams(iconWidth, iconHeight)); iconView.addView(countryView, new LinearLayout.LayoutParams(iconWidth, iconHeight));
right.addView(iconView, matchWrapParams); right.addView(iconView, matchWrapParams);
commentView = new TextView(context); commentView = new TextView(context);
commentView.setTextSize(15); commentView.setTextSize(15);
commentView.setPadding(postPadding, commentPadding, postPadding, commentPadding); commentView.setPadding(postPadding, commentPadding, postPadding, commentPadding);
right.addView(commentView, matchWrapParams); right.addView(commentView, matchWrapParams);
repliesCountView = new TextView(context); repliesCountView = new TextView(context);
// Set the drawable before the padding, because setting the background resets the padding // Set the drawable before the padding, because setting the background resets the padding
// This behavior differs with 4.4 / 4.1 // This behavior differs with 4.4 / 4.1
Utils.setPressedDrawable(repliesCountView); Utils.setPressedDrawable(repliesCountView);
repliesCountView.setTextColor(Color.argb(255, 100, 100, 100)); repliesCountView.setTextColor(Color.argb(255, 100, 100, 100));
repliesCountView.setPadding(postPadding, postPadding, postPadding, postPadding); repliesCountView.setPadding(postPadding, postPadding, postPadding, postPadding);
repliesCountView.setTextSize(14); repliesCountView.setTextSize(14);
right.addView(repliesCountView, wrapParams); right.addView(repliesCountView, wrapParams);
full.addView(right, matchWrapParams); full.addView(right, matchWrapParams);
addView(full, matchParams); addView(full, matchParams);
full.setOnClickListener(this);
full.setOnLongClickListener(this);
} }
private IDColor computeIDColor(String id) {
// Stolen from the 4chan extension
int hash = post.id.hashCode();
int r = (hash >> 24) & 0xff;
int g = (hash >> 16) & 0xff;
int b = (hash >> 8) & 0xff;
IDColor c = new IDColor();
c.color = (0xff << 24) + (r << 16) + (g << 8) + b;
c.backgroundColor = ((r * 0.299f) + (g * 0.587f) + (b * 0.114f)) > 125 ? 0xff636363 : 0x00000000;
return c;
}
public void onLinkableClick(PostLinkable linkable) { public void onLinkableClick(PostLinkable linkable) {
manager.onPostLinkableClicked(linkable); manager.onPostLinkableClicked(linkable);
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
manager.onPostClicked(post); manager.onPostClicked(post);
@ -353,13 +309,56 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
@Override @Override
public boolean onLongClick(View v) { public boolean onLongClick(View v) {
manager.onPostLongClicked(post); manager.onPostLongClicked(post);
return true; return true;
} }
private static class IDColor { private class PostViewMovementMethod extends LinkMovementMethod {
public int color; @Override
public int backgroundColor; public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
return true;
} else {
Selection.removeSelection(buffer);
// Changed this to propagate events
PostView.this.onTouchEvent(event);
return true;
}
} else {
PostView.this.onTouchEvent(event);
return true;
}
// return Touch.onTouchEvent(widget, buffer, event);
}
} }
} }

Loading…
Cancel
Save