Add icons dynamically to a post

Add support for since4pass icons. An option for this will come later when we have per-site options figured out.
multisite
Floens 9 years ago
parent 9f462aa416
commit 7dc977eedf
  1. 26
      Clover/app/src/main/java/org/floens/chan/core/model/Post.java
  2. 31
      Clover/app/src/main/java/org/floens/chan/core/model/PostHttpIcon.java
  3. 4
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  4. 2
      Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java
  5. 20
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
  6. 19
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java
  7. 141
      Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java

@ -62,11 +62,7 @@ public class Post {
public final String capcode; public final String capcode;
public final String country; public final List<PostHttpIcon> httpIcons;
public final String countryName;
public final HttpUrl countryUrl;
public final boolean isSavedReply; public final boolean isSavedReply;
@ -130,9 +126,11 @@ public class Post {
time = builder.unixTimestampSeconds; time = builder.unixTimestampSeconds;
image = builder.image; image = builder.image;
country = builder.countryCode; if (builder.httpIcons != null) {
countryName = builder.countryName; httpIcons = Collections.unmodifiableList(builder.httpIcons);
countryUrl = builder.countryUrl; } else {
httpIcons = null;
}
id = builder.posterId; id = builder.posterId;
capcode = builder.moderatorCapcode; capcode = builder.moderatorCapcode;
@ -245,6 +243,8 @@ public class Post {
public String countryName; public String countryName;
public HttpUrl countryUrl; public HttpUrl countryUrl;
public List<PostHttpIcon> httpIcons;
public String posterId = ""; public String posterId = "";
public String moderatorCapcode = ""; public String moderatorCapcode = "";
@ -353,10 +353,12 @@ public class Post {
return this; return this;
} }
public Builder country(String countryCode, String countryName, HttpUrl countryUrl) { public Builder addHttpIcon(PostHttpIcon httpIcon) {
this.countryCode = countryCode; if (httpIcons == null) {
this.countryName = countryName; httpIcons = new ArrayList<>();
this.countryUrl = countryUrl; }
httpIcons.add(httpIcon);
return this; return this;
} }

@ -0,0 +1,31 @@
/*
* 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.core.model;
import okhttp3.HttpUrl;
public class PostHttpIcon {
public final HttpUrl url;
public final String name;
public PostHttpIcon(HttpUrl url, String name) {
this.url = url;
this.name = name;
}
}

@ -669,9 +669,9 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
text += "\nTripcode: " + post.tripcode; text += "\nTripcode: " + post.tripcode;
} }
if (!TextUtils.isEmpty(post.countryName)) { /*if (!TextUtils.isEmpty(post.countryName)) {
text += "\nCountry: " + post.country + ", " + post.countryName; text += "\nCountry: " + post.country + ", " + post.countryName;
} }*/
if (!TextUtils.isEmpty(post.capcode)) { if (!TextUtils.isEmpty(post.capcode)) {
text += "\nCapcode: " + post.capcode; text += "\nCapcode: " + post.capcode;

@ -37,7 +37,7 @@ public interface SiteEndpoints {
HttpUrl thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg); HttpUrl thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg);
HttpUrl flag(Post.Builder post, String countryCode, Map<String, String> arg); HttpUrl icon(Post.Builder post, String icon, Map<String, String> arg);
HttpUrl boards(); HttpUrl boards();

@ -142,12 +142,20 @@ public class Chan4 implements Site {
} }
@Override @Override
public HttpUrl flag(Post.Builder post, String countryCode, Map<String, String> arg) { public HttpUrl icon(Post.Builder post, String icon, Map<String, String> arg) {
return s.newBuilder() HttpUrl.Builder b = s.newBuilder().addPathSegment("image");
.addPathSegment("image")
.addPathSegment("country") switch (icon) {
.addPathSegment(countryCode.toLowerCase(Locale.ENGLISH) + ".gif") case "country":
.build(); b.addPathSegment("country");
b.addPathSegment(arg.get("country_code").toLowerCase(Locale.ENGLISH) + ".gif");
break;
case "since4pass":
b.addPathSegment("minileaf.gif");
break;
}
return b.build();
} }
@Override @Override

@ -28,6 +28,7 @@ import org.floens.chan.core.manager.FilterEngine;
import org.floens.chan.core.model.Filter; import org.floens.chan.core.model.Filter;
import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post; import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostHttpIcon;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.core.net.JsonReaderRequest; import org.floens.chan.core.net.JsonReaderRequest;
import org.floens.chan.core.site.SiteEndpoints; import org.floens.chan.core.site.SiteEndpoints;
@ -35,7 +36,6 @@ import org.floens.chan.utils.Time;
import org.jsoup.parser.Parser; import org.jsoup.parser.Parser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -372,6 +372,9 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
String countryCode = null; String countryCode = null;
String countryName = null; String countryName = null;
// 4chan pass leaf
int since4pass = 0;
reader.beginObject(); reader.beginObject();
while (reader.hasNext()) { while (reader.hasNext()) {
String key = reader.nextName(); String key = reader.nextName();
@ -454,6 +457,9 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
case "capcode": case "capcode":
builder.moderatorCapcode(reader.nextString()); builder.moderatorCapcode(reader.nextString());
break; break;
case "since4pass":
since4pass = reader.nextInt();
break;
default: default:
// Unknown/ignored key // Unknown/ignored key
reader.skipValue(); reader.skipValue();
@ -499,8 +505,15 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
} }
if (countryCode != null && countryName != null) { if (countryCode != null && countryName != null) {
HttpUrl countryUrl = endpoints.flag(builder, countryCode, Collections.<String, String>emptyMap()); Map<String, String> arg = new HashMap<>(1);
builder.country(countryCode, countryName, countryUrl); arg.put("country_code", countryCode);
HttpUrl countryUrl = endpoints.icon(builder, "country", arg);
builder.addHttpIcon(new PostHttpIcon(countryUrl, countryName));
}
if (since4pass != 0) {
HttpUrl iconUrl = endpoints.icon(builder, "since4pass", null);
builder.addHttpIcon(new PostHttpIcon(iconUrl, String.valueOf(since4pass)));
} }
queue.toParse.add(builder); queue.toParse.add(builder);

@ -53,6 +53,7 @@ import com.android.volley.toolbox.ImageLoader;
import org.floens.chan.R; import org.floens.chan.R;
import org.floens.chan.core.model.Post; import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostHttpIcon;
import org.floens.chan.core.model.PostImage; import org.floens.chan.core.model.PostImage;
import org.floens.chan.core.model.PostLinkable; import org.floens.chan.core.model.PostLinkable;
import org.floens.chan.core.settings.ChanSettings; import org.floens.chan.core.settings.ChanSettings;
@ -74,6 +75,8 @@ import java.text.BreakIterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import okhttp3.HttpUrl;
import static android.text.TextUtils.isEmpty; import static android.text.TextUtils.isEmpty;
import static org.floens.chan.Chan.getGraph; import static org.floens.chan.Chan.getGraph;
import static org.floens.chan.utils.AndroidUtils.ROBOTO_CONDENSED_REGULAR; import static org.floens.chan.utils.AndroidUtils.ROBOTO_CONDENSED_REGULAR;
@ -97,7 +100,7 @@ public class PostCell extends LinearLayout implements PostCellInterface {
private boolean commentClickable = false; private boolean commentClickable = false;
private int detailsSizePx; private int detailsSizePx;
private int countrySizePx; private int iconSizePx;
private int paddingPx; private int paddingPx;
private boolean threadMode; private boolean threadMode;
private boolean ignoreNextOnClick; private boolean ignoreNextOnClick;
@ -155,7 +158,7 @@ public class PostCell extends LinearLayout implements PostCellInterface {
title.setTextSize(textSizeSp); title.setTextSize(textSizeSp);
title.setPadding(paddingPx, paddingPx, dp(52), 0); title.setPadding(paddingPx, paddingPx, dp(52), 0);
countrySizePx = sp(textSizeSp - 3); iconSizePx = sp(textSizeSp - 3);
icons.setHeight(sp(textSizeSp)); icons.setHeight(sp(textSizeSp));
icons.setSpacing(dp(4)); icons.setSpacing(dp(4));
icons.setPadding(paddingPx, dp(4), paddingPx, 0); icons.setPadding(paddingPx, dp(4), paddingPx, 0);
@ -398,12 +401,10 @@ public class PostCell extends LinearLayout implements PostCellInterface {
icons.set(PostIcons.CLOSED, post.isClosed()); icons.set(PostIcons.CLOSED, post.isClosed());
icons.set(PostIcons.DELETED, post.deleted.get()); icons.set(PostIcons.DELETED, post.deleted.get());
icons.set(PostIcons.ARCHIVED, post.isArchived()); icons.set(PostIcons.ARCHIVED, post.isArchived());
icons.set(PostIcons.HTTP_ICONS, post.httpIcons != null);
if (!isEmpty(post.country)) { if (post.httpIcons != null) {
icons.set(PostIcons.COUNTRY, true); icons.setHttpIcons(post.httpIcons, theme, iconSizePx);
icons.showCountry(post, theme, countrySizePx);
} else {
icons.set(PostIcons.COUNTRY, false);
} }
icons.apply(); icons.apply();
@ -469,7 +470,7 @@ public class PostCell extends LinearLayout implements PostCellInterface {
private void unbindPost(Post post) { private void unbindPost(Post post) {
bound = false; bound = false;
icons.cancelCountryRequest(); icons.cancelRequests();
setPostLinkableListener(post, false); setPostLinkableListener(post, false);
} }
@ -609,7 +610,7 @@ public class PostCell extends LinearLayout implements PostCellInterface {
private static final int CLOSED = 0x2; private static final int CLOSED = 0x2;
private static final int DELETED = 0x4; private static final int DELETED = 0x4;
private static final int ARCHIVED = 0x8; private static final int ARCHIVED = 0x8;
private static final int COUNTRY = 0x10; private static final int HTTP_ICONS = 0x10;
private int height; private int height;
private int spacing; private int spacing;
@ -619,28 +620,23 @@ public class PostCell extends LinearLayout implements PostCellInterface {
private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Rect textRect = new Rect(); private Rect textRect = new Rect();
private ImageLoader.ImageContainer countryIconRequest;
private Bitmap countryIcon; private int httpIconTextColor;
private String countryName; private int httpIconTextSize;
private int countryTextColor;
private int countryTextSize; private List<PostIconsHttpIcon> httpIcons;
public PostIcons(Context context) { public PostIcons(Context context) {
super(context); this(context, null);
init();
} }
public PostIcons(Context context, AttributeSet attrs) { public PostIcons(Context context, AttributeSet attrs) {
super(context, attrs); this(context, attrs, 0);
init();
} }
public PostIcons(Context context, AttributeSet attrs, int defStyleAttr) { public PostIcons(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr); super(context, attrs, defStyleAttr);
init();
}
private void init() {
textPaint.setTypeface(Typeface.create((String) null, Typeface.ITALIC)); textPaint.setTypeface(Typeface.create((String) null, Typeface.ITALIC));
setVisibility(View.GONE); setVisibility(View.GONE);
} }
@ -655,10 +651,12 @@ public class PostCell extends LinearLayout implements PostCellInterface {
public void edit() { public void edit() {
previousIcons = icons; previousIcons = icons;
httpIcons = null;
} }
public void apply() { public void apply() {
if (previousIcons != icons) { if (previousIcons != icons) {
// Require a layout only if the height changed
if (previousIcons == 0 || icons == 0) { if (previousIcons == 0 || icons == 0) {
setVisibility(icons == 0 ? View.GONE : View.VISIBLE); setVisibility(icons == 0 ? View.GONE : View.VISIBLE);
requestLayout(); requestLayout();
@ -668,34 +666,24 @@ public class PostCell extends LinearLayout implements PostCellInterface {
} }
} }
public void showCountry(final Post post, final Theme theme, int textSize) { public void setHttpIcons(List<PostHttpIcon> icons, Theme theme, int size) {
countryName = post.countryName; httpIconTextColor = theme.detailsColor;
countryTextColor = theme.detailsColor; httpIconTextSize = size;
countryTextSize = textSize; httpIcons = new ArrayList<>(icons.size());
for (int i = 0; i < icons.size(); i++) {
countryIconRequest = getGraph().getImageLoader().get(post.countryUrl.toString(), new ImageLoader.ImageListener() { PostHttpIcon icon = icons.get(i);
@Override PostIconsHttpIcon j = new PostIconsHttpIcon(this, icon.name, icon.url);
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) { httpIcons.add(j);
if (response.getBitmap() != null) { j.request();
countryIcon = response.getBitmap(); }
invalidate();
}
}
@Override
public void onErrorResponse(VolleyError error) {
}
});
} }
public void cancelCountryRequest() { public void cancelRequests() {
if (countryIconRequest != null) { if (httpIcons != null) {
countryIconRequest.cancelRequest(); for (int i = 0; i < httpIcons.size(); i++) {
countryIconRequest = null; PostIconsHttpIcon httpIcon = httpIcons.get(i);
countryIcon = null; httpIcon.cancel();
countryName = null; }
countryTextColor = 0;
} }
} }
@ -742,14 +730,20 @@ public class PostCell extends LinearLayout implements PostCellInterface {
offset += drawBitmap(canvas, archivedIcon, offset); offset += drawBitmap(canvas, archivedIcon, offset);
} }
if (get(COUNTRY) && countryIcon != null) { if (get(HTTP_ICONS)) {
offset += drawBitmap(canvas, countryIcon, offset); for (int i = 0; i < httpIcons.size(); i++) {
PostIconsHttpIcon httpIcon = httpIcons.get(i);
textPaint.setColor(countryTextColor); if (httpIcon.bitmap != null) {
textPaint.setTextSize(countryTextSize); offset += drawBitmap(canvas, httpIcon.bitmap, offset);
textPaint.getTextBounds(countryName, 0, countryName.length(), textRect);
float y = height / 2f - textRect.exactCenterY(); textPaint.setColor(httpIconTextColor);
canvas.drawText(countryName, offset, y, textPaint); textPaint.setTextSize(httpIconTextSize);
textPaint.getTextBounds(httpIcon.name, 0, httpIcon.name.length(), textRect);
float y = height / 2f - textRect.exactCenterY();
canvas.drawText(httpIcon.name, offset, y, textPaint);
offset += textRect.width() + spacing;
}
}
} }
canvas.restore(); canvas.restore();
@ -763,4 +757,41 @@ public class PostCell extends LinearLayout implements PostCellInterface {
return width + spacing; return width + spacing;
} }
} }
private static class PostIconsHttpIcon implements ImageLoader.ImageListener {
private final PostIcons postIcons;
private final String name;
private final HttpUrl url;
private ImageLoader.ImageContainer request;
private Bitmap bitmap;
private PostIconsHttpIcon(PostIcons postIcons, String name, HttpUrl url) {
this.postIcons = postIcons;
this.name = name;
this.url = url;
}
private void request() {
request = getGraph().getImageLoader().get(url.toString(), this);
}
private void cancel() {
if (request != null) {
request.cancelRequest();
request = null;
}
}
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null) {
bitmap = response.getBitmap();
postIcons.invalidate();
}
}
@Override
public void onErrorResponse(VolleyError error) {
}
}
} }

Loading…
Cancel
Save