Add PostStubCell, for either list or card mode.

filtering
Floens 10 years ago
parent 82ff3de6c8
commit fe352c516f
  1. 13
      Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java
  2. 5
      Clover/app/src/main/java/org/floens/chan/core/manager/FilterEngine.java
  3. 7
      Clover/app/src/main/java/org/floens/chan/core/net/ChanReaderRequest.java
  4. 22
      Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java
  5. 12
      Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java
  6. 12
      Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java
  7. 2
      Clover/app/src/main/java/org/floens/chan/ui/cell/PostCellInterface.java
  8. 197
      Clover/app/src/main/java/org/floens/chan/ui/cell/PostStubCell.java
  9. 1
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  10. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/PostRepliesController.java
  11. 3
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThemeSettingsController.java
  12. 62
      Clover/app/src/main/res/layout/cell_post_stub.xml

@ -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.<br>
* This is done on a background thread for performance, even when it is UI code.<br>
* 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,8 +127,11 @@ public class ChanParser {
if (!TextUtils.isEmpty(post.subject)) {
post.subjectSpan = new SpannableString(post.subject);
// 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")) {
post.nameSpan = new SpannableString(post.name);

@ -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) {

@ -318,11 +318,12 @@ public class ChanReaderRequest extends JsonReaderRequest<ChanReaderRequest.ChanR
if (cached != null) {
return cached;
} else {
// Process the filters before finish, because parsing the html is dependent on filter matches
processPostFilter(post);
if (!post.finish()) {
Logger.e(TAG, "Incorrect data about post received for post " + post.no);
return null;
} else {
processPostFilter(post);
return post;
}
}
@ -341,10 +342,14 @@ public class ChanReaderRequest extends JsonReaderRequest<ChanReaderRequest.ChanR
post.filterHighlightedColor = filter.color;
break;
case HIDE:
if (!loadable.isThreadMode()) {
post.filterStub = true;
}
break;
case REMOVE:
if (!loadable.isThreadMode()) {
post.filterRemove = true;
}
break;
}
}

@ -35,6 +35,7 @@ import java.util.List;
public class PostAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
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<RecyclerView.ViewHolder> {
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<RecyclerView.ViewHolder> {
@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<RecyclerView.ViewHolder> {
@Override
public int getItemViewType(int position) {
if (showStatusView()) {
if (position == getItemCount() - 1) {
if (showStatusView() && position == getItemCount() - 1) {
return TYPE_STATUS;
} else {
return TYPE_POST;
}
Post post = displayList.get(position);
if (post.filterStub) {
return TYPE_POST_STUB;
} 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;

@ -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)) {

@ -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;

@ -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();

@ -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 <http://www.gnu.org/licenses/>.
*/
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<FloatingMenuItem> 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;
}
}

@ -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"));
}
}));

@ -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;
}

@ -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;

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?><!--
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 <http://www.gnu.org/licenses/>.
-->
<org.floens.chan.ui.cell.PostStubCell xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/item_background"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables,ContentDescription">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/options"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@id/options"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="?attr/text_color_secondary" />
<ImageView
android:id="@+id/options"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_gravity="top|right"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingRight="5dp"
android:paddingTop="5dp"
android:src="?post_options_drawable"
tools:ignore="ContentDescription,RtlHardcoded" />
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@id/options"
android:background="?attr/divider_color" />
</org.floens.chan.ui.cell.PostStubCell>
Loading…
Cancel
Save