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 country;
public final String countryName;
public final HttpUrl countryUrl;
public final List<PostHttpIcon> httpIcons;
public final boolean isSavedReply;
@ -130,9 +126,11 @@ public class Post {
time = builder.unixTimestampSeconds;
image = builder.image;
country = builder.countryCode;
countryName = builder.countryName;
countryUrl = builder.countryUrl;
if (builder.httpIcons != null) {
httpIcons = Collections.unmodifiableList(builder.httpIcons);
} else {
httpIcons = null;
}
id = builder.posterId;
capcode = builder.moderatorCapcode;
@ -245,6 +243,8 @@ public class Post {
public String countryName;
public HttpUrl countryUrl;
public List<PostHttpIcon> httpIcons;
public String posterId = "";
public String moderatorCapcode = "";
@ -353,10 +353,12 @@ public class Post {
return this;
}
public Builder country(String countryCode, String countryName, HttpUrl countryUrl) {
this.countryCode = countryCode;
this.countryName = countryName;
this.countryUrl = countryUrl;
public Builder addHttpIcon(PostHttpIcon httpIcon) {
if (httpIcons == null) {
httpIcons = new ArrayList<>();
}
httpIcons.add(httpIcon);
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;
}
if (!TextUtils.isEmpty(post.countryName)) {
/*if (!TextUtils.isEmpty(post.countryName)) {
text += "\nCountry: " + post.country + ", " + post.countryName;
}
}*/
if (!TextUtils.isEmpty(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 flag(Post.Builder post, String countryCode, Map<String, String> arg);
HttpUrl icon(Post.Builder post, String icon, Map<String, String> arg);
HttpUrl boards();

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

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

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