From 7dc977eedf3b06d71a8a7790d3713c417639751f Mon Sep 17 00:00:00 2001 From: Floens Date: Fri, 6 Jan 2017 23:26:04 +0100 Subject: [PATCH] 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. --- .../java/org/floens/chan/core/model/Post.java | 26 ++-- .../floens/chan/core/model/PostHttpIcon.java | 31 ++++ .../chan/core/presenter/ThreadPresenter.java | 4 +- .../floens/chan/core/site/SiteEndpoints.java | 2 +- .../chan/core/site/sites/chan4/Chan4.java | 20 ++- .../site/sites/chan4/Chan4ReaderRequest.java | 19 ++- .../org/floens/chan/ui/cell/PostCell.java | 141 +++++++++++------- 7 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 Clover/app/src/main/java/org/floens/chan/core/model/PostHttpIcon.java diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java b/Clover/app/src/main/java/org/floens/chan/core/model/Post.java index 0ed7bbb8..944a2206 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/Post.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 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 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; } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/PostHttpIcon.java b/Clover/app/src/main/java/org/floens/chan/core/model/PostHttpIcon.java new file mode 100644 index 00000000..3ddbf0b7 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/model/PostHttpIcon.java @@ -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 . + */ +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; + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index 153593f4..3799fc31 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -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; diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java b/Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java index 756d2958..ab199c95 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java @@ -37,7 +37,7 @@ public interface SiteEndpoints { HttpUrl thumbnailUrl(Post.Builder post, boolean spoiler, Map arg); - HttpUrl flag(Post.Builder post, String countryCode, Map arg); + HttpUrl icon(Post.Builder post, String icon, Map arg); HttpUrl boards(); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java index 2b68ac42..0f70d673 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java @@ -142,12 +142,20 @@ public class Chan4 implements Site { } @Override - public HttpUrl flag(Post.Builder post, String countryCode, Map arg) { - return s.newBuilder() - .addPathSegment("image") - .addPathSegment("country") - .addPathSegment(countryCode.toLowerCase(Locale.ENGLISH) + ".gif") - .build(); + public HttpUrl icon(Post.Builder post, String icon, Map 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 diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java index c203bbed..2a04e0e8 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java @@ -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 { 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 { 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 { } if (countryCode != null && countryName != null) { - HttpUrl countryUrl = endpoints.flag(builder, countryCode, Collections.emptyMap()); - builder.country(countryCode, countryName, countryUrl); + Map 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); 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 c9d16d2b..80de3f75 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 @@ -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 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 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) { + } + } }