diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java
index 4f13f147..8e935e37 100644
--- a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java
+++ b/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java
@@ -30,10 +30,10 @@ import android.text.style.TypefaceSpan;
import android.text.style.UnderlineSpan;
import org.floens.chan.Chan;
+import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostLinkable;
import org.floens.chan.core.settings.ChanSettings;
-import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.ui.theme.Theme;
import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.utils.Logger;
@@ -102,6 +102,14 @@ public class ChanParser {
}
}
+ /**
+ * Parse the comment, subject, tripcodes, names etc. as spannables.
+ * This is done on a background thread for performance, even when it is UI code.
+ * The results will be placed on the Post.*Span members.
+ *
+ * @param theme Theme to use for parsing
+ * @param post Post to get data from
+ */
private void parseSpans(Theme theme, Post post) {
boolean anonymize = ChanSettings.anonymize.get();
boolean anonymizeIds = ChanSettings.anonymizeIds.get();
@@ -119,7 +127,10 @@ public class ChanParser {
if (!TextUtils.isEmpty(post.subject)) {
post.subjectSpan = new SpannableString(post.subject);
- post.subjectSpan.setSpan(new ForegroundColorSpan(theme.subjectColor), 0, post.subjectSpan.length(), 0);
+ // Do not set another color when the post is in stub mode, it sets text_color_secondary
+ if (!post.filterStub) {
+ post.subjectSpan.setSpan(new ForegroundColorSpan(theme.subjectColor), 0, post.subjectSpan.length(), 0);
+ }
}
if (!TextUtils.isEmpty(post.name) && !post.name.equals("Anonymous")) {
diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java b/Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java
index c8189d20..f626a625 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java
@@ -148,6 +148,7 @@ public class FilterEngine {
}
public boolean matches(Filter filter, Post post) {
+ // Post has not been finish()ed yet, account for invalid values
String text = null;
FilterType type = FilterType.forId(filter.type);
switch (type) {
@@ -158,7 +159,7 @@ public class FilterEngine {
text = post.name;
break;
case COMMENT:
- text = post.comment.toString();
+ text = post.comment == null ? null : post.comment.toString();
break;
case ID:
text = post.id;
@@ -171,7 +172,7 @@ public class FilterEngine {
break;
}
- return matches(filter, text, false);
+ return !TextUtils.isEmpty(text) && matches(filter, text, false);
}
public boolean matches(Filter filter, String text, boolean forceCompile) {
diff --git a/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java b/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java
index 7ad356a8..c97f2de2 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java
@@ -318,11 +318,12 @@ public class ChanReaderRequest extends JsonReaderRequest {
private static final int TYPE_POST = 0;
private static final int TYPE_STATUS = 1;
+ private static final int TYPE_POST_STUB = 2;
private final PostAdapterCallback postAdapterCallback;
private final PostCellInterface.PostCellCallback postCellCallback;
@@ -76,6 +77,8 @@ public class PostAdapter extends RecyclerView.Adapter {
PostCellInterface postCell = (PostCellInterface) LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
return new PostViewHolder(postCell);
+ } else if (viewType == TYPE_POST_STUB) {
+ return new PostViewHolder((PostCellInterface) LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_post_stub, parent, false));
} else {
StatusViewHolder statusViewHolder = new StatusViewHolder((ThreadStatusCell) LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_thread_status, parent, false));
statusViewHolder.threadStatusCell.setCallback(statusCellCallback);
@@ -86,12 +89,13 @@ public class PostAdapter extends RecyclerView.Adapter {
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- if (getItemViewType(position) == TYPE_POST) {
+ int itemViewType = getItemViewType(position);
+ if (itemViewType == TYPE_POST || itemViewType == TYPE_POST_STUB) {
PostViewHolder postViewHolder = (PostViewHolder) holder;
Post post = displayList.get(position);
boolean highlight = post == highlightedPost || post.id.equals(highlightedPostId) || post.no == highlightedPostNo || post.tripcode.equals(highlightedPostTripcode);
- postViewHolder.postView.setPost(null, post, postCellCallback, highlight, -1);
- } else if (getItemViewType(position) == TYPE_STATUS) {
+ postViewHolder.postView.setPost(null, post, postCellCallback, highlight, -1, postViewMode);
+ } else if (itemViewType == TYPE_STATUS) {
((StatusViewHolder) holder).threadStatusCell.update();
onScrolledToBottom();
}
@@ -108,20 +112,22 @@ public class PostAdapter extends RecyclerView.Adapter {
@Override
public int getItemViewType(int position) {
- if (showStatusView()) {
- if (position == getItemCount() - 1) {
- return TYPE_STATUS;
+ if (showStatusView() && position == getItemCount() - 1) {
+ return TYPE_STATUS;
+ } else {
+ Post post = displayList.get(position);
+ if (post.filterStub) {
+ return TYPE_POST_STUB;
} else {
return TYPE_POST;
}
- } else {
- return TYPE_POST;
}
}
@Override
public long getItemId(int position) {
- if (getItemViewType(position) != TYPE_POST) {
+ int itemViewType = getItemViewType(position);
+ if (itemViewType == TYPE_STATUS) {
return -1;
} else {
return displayList.get(position).no;
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java
index 48232f93..29411638 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java
@@ -55,7 +55,7 @@ public class CardPostCell extends CardView implements PostCellInterface, View.On
private FastTextView comment;
private TextView replies;
private ImageView options;
- private View colorLeft;
+ private View filterMatchColor;
public CardPostCell(Context context) {
super(context);
@@ -80,7 +80,7 @@ public class CardPostCell extends CardView implements PostCellInterface, View.On
replies = (TextView) findViewById(R.id.replies);
options = (ImageView) findViewById(R.id.options);
setRoundItemBackground(options);
- colorLeft = findViewById(R.id.filter_match_color);
+ filterMatchColor = findViewById(R.id.filter_match_color);
int textSizeSp = Integer.parseInt(ChanSettings.fontSize.get());
title.setTextSize(textSizeSp);
@@ -139,7 +139,7 @@ public class CardPostCell extends CardView implements PostCellInterface, View.On
}
}
- public void setPost(Theme theme, final Post post, PostCellInterface.PostCellCallback callback, boolean highlighted, int markedNo) {
+ public void setPost(Theme theme, final Post post, PostCellInterface.PostCellCallback callback, boolean highlighted, int markedNo, PostCellInterface.PostViewMode postViewMode) {
if (this.post == post) {
return;
}
@@ -186,10 +186,10 @@ public class CardPostCell extends CardView implements PostCellInterface, View.On
}
if (post.filterHighlightedColor != 0) {
- colorLeft.setVisibility(View.VISIBLE);
- colorLeft.setBackgroundColor(post.filterHighlightedColor);
+ filterMatchColor.setVisibility(View.VISIBLE);
+ filterMatchColor.setBackgroundColor(post.filterHighlightedColor);
} else {
- colorLeft.setVisibility(View.GONE);
+ filterMatchColor.setVisibility(View.GONE);
}
if (!TextUtils.isEmpty(post.subjectSpan)) {
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java
index 18d4ad98..47369087 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java
@@ -224,7 +224,7 @@ public class PostCell extends LinearLayout implements PostCellInterface, PostLin
}
}
- public void setPost(Theme theme, final Post post, PostCellInterface.PostCellCallback callback, boolean highlighted, int markedNo) {
+ public void setPost(Theme theme, final Post post, PostCellInterface.PostCellCallback callback, boolean highlighted, int markedNo, PostCellInterface.PostViewMode postViewMode) {
if (this.post == post && this.highlighted == highlighted && this.markedNo == markedNo) {
return;
}
@@ -291,7 +291,7 @@ public class PostCell extends LinearLayout implements PostCellInterface, PostLin
colorLeft.setVisibility(View.GONE);
}
- if (post.hasImage && !post.filterStub) {
+ if (post.hasImage) {
thumbnailView.setVisibility(View.VISIBLE);
thumbnailView.setUrl(post.thumbnailUrl, thumbnailView.getLayoutParams().width, thumbnailView.getLayoutParams().height);
} else {
@@ -353,16 +353,14 @@ public class PostCell extends LinearLayout implements PostCellInterface, PostLin
}
CharSequence commentText;
- if (post.filterStub) {
- commentText = null;
- } else if (post.comment.length() > COMMENT_MAX_LENGTH_BOARD && !threadMode) {
+ if (post.comment.length() > COMMENT_MAX_LENGTH_BOARD && !threadMode) {
commentText = post.comment.subSequence(0, COMMENT_MAX_LENGTH_BOARD);
} else {
commentText = post.comment;
}
comment.setText(commentText);
- comment.setVisibility(TextUtils.isEmpty(commentText) ? GONE : VISIBLE);
+ comment.setVisibility(TextUtils.isEmpty(commentText) && !post.hasImage ? GONE : VISIBLE);
if (commentClickable != threadMode) {
commentClickable = threadMode;
@@ -379,7 +377,7 @@ public class PostCell extends LinearLayout implements PostCellInterface, PostLin
}
}
- if (!post.filterStub && ((!threadMode && post.replies > 0) || (post.repliesFrom.size() > 0))) {
+ if ((!threadMode && post.replies > 0) || (post.repliesFrom.size() > 0)) {
replies.setVisibility(View.VISIBLE);
int replyCount = threadMode ? post.repliesFrom.size() : post.replies;
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCellInterface.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCellInterface.java
index 34df8c56..938005fe 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCellInterface.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostCellInterface.java
@@ -27,7 +27,7 @@ import org.floens.chan.ui.view.ThumbnailView;
import java.util.List;
public interface PostCellInterface {
- void setPost(Theme theme, Post post, PostCellCallback callback, boolean highlighted, int markedN);
+ void setPost(Theme theme, Post post, PostCellCallback callback, boolean highlighted, int markedNo, PostCellInterface.PostViewMode postViewMode);
Post getPost();
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/PostStubCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostStubCell.java
new file mode 100644
index 00000000..8d678f2a
--- /dev/null
+++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/PostStubCell.java
@@ -0,0 +1,197 @@
+/*
+ * Clover - 4chan browser https://github.com/Floens/Clover/
+ * Copyright (C) 2014 Floens
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.floens.chan.ui.cell;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import org.floens.chan.R;
+import org.floens.chan.core.model.Post;
+import org.floens.chan.core.settings.ChanSettings;
+import org.floens.chan.ui.theme.Theme;
+import org.floens.chan.ui.theme.ThemeHelper;
+import org.floens.chan.ui.view.FloatingMenu;
+import org.floens.chan.ui.view.FloatingMenuItem;
+import org.floens.chan.ui.view.ThumbnailView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.floens.chan.utils.AndroidUtils.dp;
+import static org.floens.chan.utils.AndroidUtils.setRoundItemBackground;
+
+public class PostStubCell extends RelativeLayout implements PostCellInterface, View.OnClickListener {
+ private static final int TITLE_MAX_LENGTH = 100;
+
+ private boolean bound;
+ private Theme theme;
+ private Post post;
+ private PostViewMode postViewMode;
+ private PostCellInterface.PostCellCallback callback;
+
+ private TextView title;
+ private ImageView options;
+ private View divider;
+
+ public PostStubCell(Context context) {
+ super(context);
+ }
+
+ public PostStubCell(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public PostStubCell(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ title = (TextView) findViewById(R.id.title);
+ options = (ImageView) findViewById(R.id.options);
+ setRoundItemBackground(options);
+ divider = findViewById(R.id.divider);
+
+ int textSizeSp = Integer.parseInt(ChanSettings.fontSize.get());
+ title.setTextSize(textSizeSp);
+
+ int paddingPx = dp(textSizeSp - 6);
+ title.setPadding(paddingPx, 0, 0, 0);
+
+ RelativeLayout.LayoutParams dividerParams = (RelativeLayout.LayoutParams) divider.getLayoutParams();
+ dividerParams.leftMargin = paddingPx;
+ dividerParams.rightMargin = paddingPx;
+ divider.setLayoutParams(dividerParams);
+
+ setOnClickListener(this);
+
+ options.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ List items = new ArrayList<>();
+
+ callback.onPopulatePostOptions(post, items);
+
+ FloatingMenu menu = new FloatingMenu(getContext(), v, items);
+ menu.setCallback(new FloatingMenu.FloatingMenuCallback() {
+ @Override
+ public void onFloatingMenuItemClicked(FloatingMenu menu, FloatingMenuItem item) {
+ callback.onPostOptionClicked(post, item.getId());
+ }
+
+ @Override
+ public void onFloatingMenuDismissed(FloatingMenu menu) {
+ }
+ });
+ menu.show();
+ }
+ });
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == this) {
+ callback.onPostClicked(post);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (post != null && bound) {
+ unbindPost(post);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ if (post != null && !bound) {
+ bindPost(theme, post);
+ }
+ }
+
+ public void setPost(Theme theme, final Post post, PostCellInterface.PostCellCallback callback, boolean highlighted, int markedNo, PostCellInterface.PostViewMode postViewMode) {
+ if (this.post == post) {
+ return;
+ }
+
+ if (theme == null) {
+ theme = ThemeHelper.theme();
+ }
+
+ if (this.post != null && bound) {
+ unbindPost(this.post);
+ this.post = null;
+ }
+
+ this.theme = theme;
+ this.post = post;
+ this.callback = callback;
+ this.postViewMode = postViewMode;
+
+ bindPost(theme, post);
+ }
+
+ public Post getPost() {
+ return post;
+ }
+
+ public ThumbnailView getThumbnailView() {
+ return null;
+ }
+
+ @Override
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ private void bindPost(Theme theme, Post post) {
+ bound = true;
+
+ if (!TextUtils.isEmpty(post.subjectSpan)) {
+ title.setText(post.subjectSpan);
+ } else {
+ CharSequence titleText;
+ if (post.comment.length() > TITLE_MAX_LENGTH) {
+ titleText = post.comment.subSequence(0, TITLE_MAX_LENGTH);
+ } else {
+ titleText = post.comment;
+ }
+ title.setText(titleText);
+ }
+
+ divider.setVisibility(postViewMode == PostViewMode.CARD ? GONE : VISIBLE);
+ }
+
+ private void unbindPost(Post post) {
+ bound = false;
+ }
+}
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
index 8657ff52..c39e3d08 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
@@ -195,6 +195,7 @@ public class MainSettingsController extends SettingsController implements Toolba
public void onClick(View v) {
Chan.getDatabaseManager().clearAllThreadHides();
Toast.makeText(context, R.string.setting_cleared_thread_hides, Toast.LENGTH_LONG).show();
+ EventBus.getDefault().post(new RefreshUIMessage("clearhides"));
}
}));
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java
index 65e4b31c..2337ee1f 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java
@@ -177,7 +177,7 @@ public class PostRepliesController extends Controller {
}
final Post p = getItem(position);
- postCell.setPost(null, p, presenter, false, data.forPost.no);
+ postCell.setPost(null, p, presenter, false, data.forPost.no, PostCellInterface.PostViewMode.LIST);
return (View) postCell;
}
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java
index 6af83585..1adf0fa4 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java
@@ -40,6 +40,7 @@ import org.floens.chan.core.model.PostLinkable;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.cell.PostCell;
+import org.floens.chan.ui.cell.PostCellInterface;
import org.floens.chan.ui.theme.Theme;
import org.floens.chan.ui.theme.ThemeHelper;
import org.floens.chan.ui.toolbar.NavigationItem;
@@ -252,7 +253,7 @@ public class ThemeSettingsController extends Controller implements View.OnClickL
themeContext.getResources().getDimensionPixelSize(R.dimen.toolbar_height)));
PostCell postCell = (PostCell) LayoutInflater.from(themeContext).inflate(R.layout.cell_post, null);
- postCell.setPost(theme, post, DUMMY_POST_CALLBACK, false, -1);
+ postCell.setPost(theme, post, DUMMY_POST_CALLBACK, false, -1, PostCellInterface.PostViewMode.LIST);
linearLayout.addView(postCell, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
return linearLayout;
diff --git a/Clover/app/src/main/res/layout/cell_post_stub.xml b/Clover/app/src/main/res/layout/cell_post_stub.xml
new file mode 100644
index 00000000..55d33272
--- /dev/null
+++ b/Clover/app/src/main/res/layout/cell_post_stub.xml
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+
+
+