From 5fc8c7b0d7a8efa7f23f2b23243c1217b92d2e47 Mon Sep 17 00:00:00 2001 From: Floens Date: Sun, 24 Dec 2017 01:34:04 +0100 Subject: [PATCH] work on 8ch parsing and abstracting the parser --- .../org/floens/chan/core/di/AppModule.java | 2 - .../core/presenter/SiteSetupPresenter.java | 4 + .../chan/core/site/common/ChanParser.java | 25 +++ .../chan/core/site/common/ChanReader.java | 2 + .../core/site/common/ChanReaderRequest.java | 6 +- .../DefaultFutabaChanParserHandler.java | 160 +++++++++++++++ .../site/common/FutabaChanParser.java} | 184 +++++------------- .../site/common/FutabaChanParserHandler.java | 36 ++++ .../core/site/common/FutabaChanReader.java | 15 ++ .../core/site/common/PostParseCallable.java | 11 +- .../chan/core/site/sites/chan8/Chan8.java | 4 +- .../site/sites/chan8/Chan8ParserHandler.java | 133 +++++++++++++ .../chan/ui/activity/StartActivity.java | 6 +- .../ui/controller/SiteSetupController.java | 3 +- .../controller/ThemeSettingsController.java | 5 +- .../chan/ui/settings/SettingsController.java | 5 +- .../java/org/floens/chan/ui/theme/Theme.java | 2 +- 17 files changed, 446 insertions(+), 157 deletions(-) create mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java create mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/common/DefaultFutabaChanParserHandler.java rename Clover/app/src/main/java/org/floens/chan/{chan/ChanParser.java => core/site/common/FutabaChanParser.java} (73%) create mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParserHandler.java create mode 100644 Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8ParserHandler.java diff --git a/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java b/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java index 5a63546a..4e253ae2 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java +++ b/Clover/app/src/main/java/org/floens/chan/core/di/AppModule.java @@ -7,7 +7,6 @@ import com.android.volley.toolbox.ImageLoader; import org.floens.chan.ChanApplication; import org.floens.chan.chan.ChanLoader; -import org.floens.chan.chan.ChanParser; import org.floens.chan.core.cache.FileCache; import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.manager.BoardManager; @@ -57,7 +56,6 @@ import dagger.Provides; injects = { // Context.class, // ApplicationContext - ChanParser.class, BoardManager.class, DatabaseManager.class, ReplyManager.class, diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java index 54f35194..5f46cdf7 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/SiteSetupPresenter.java @@ -21,6 +21,10 @@ public class SiteSetupPresenter { } public void show() { + setBoardCount(callback, site); + } + + private void setBoardCount(Callback callback, Site site) { callback.setBoardCount( databaseManager.runTaskSync( databaseManager.getDatabaseBoardManager().getSiteSavedBoards(site) diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java new file mode 100644 index 00000000..8b4f8f3f --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanParser.java @@ -0,0 +1,25 @@ +/* + * 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.site.common; + +import org.floens.chan.core.model.Post; +import org.floens.chan.ui.theme.Theme; + +public interface ChanParser { + Post parse(Theme theme, Post.Builder builder); +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReader.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReader.java index e0c98728..b80ce543 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReader.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReader.java @@ -4,6 +4,8 @@ package org.floens.chan.core.site.common; import android.util.JsonReader; public interface ChanReader { + ChanParser getParser(); + void loadThread(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception; void loadCatalog(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception; diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReaderRequest.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReaderRequest.java index 5302ca54..1a22632a 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReaderRequest.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/ChanReaderRequest.java @@ -21,7 +21,6 @@ import android.util.JsonReader; import org.floens.chan.chan.ChanLoaderRequestParams; import org.floens.chan.chan.ChanLoaderResponse; -import org.floens.chan.chan.ChanParser; import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.database.DatabaseSavedReplyManager; import org.floens.chan.core.manager.FilterEngine; @@ -70,9 +69,6 @@ public class ChanReaderRequest extends JsonReaderRequest { @Inject FilterEngine filterEngine; - @Inject - ChanParser chanParser; - private Loadable loadable; private List cached; private ChanReader reader; @@ -181,7 +177,7 @@ public class ChanReaderRequest extends JsonReaderRequest { List> tasks = new ArrayList<>(toParse.size()); for (int i = 0; i < toParse.size(); i++) { Post.Builder post = toParse.get(i); - tasks.add(new PostParseCallable(filterEngine, filters, databaseSavedReplyManager, post, chanParser)); + tasks.add(new PostParseCallable(filterEngine, filters, databaseSavedReplyManager, post, reader)); } if (!tasks.isEmpty()) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/DefaultFutabaChanParserHandler.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/DefaultFutabaChanParserHandler.java new file mode 100644 index 00000000..b64aa1f4 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/DefaultFutabaChanParserHandler.java @@ -0,0 +1,160 @@ +/* + * 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.site.common; + +import android.graphics.Typeface; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.StrikethroughSpan; +import android.text.style.StyleSpan; + +import org.floens.chan.core.model.Post; +import org.floens.chan.core.model.PostLinkable; +import org.floens.chan.ui.span.ForegroundColorSpanHashed; +import org.floens.chan.ui.theme.Theme; +import org.jsoup.nodes.Element; + +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DefaultFutabaChanParserHandler implements FutabaChanParserHandler { + private static final Pattern COLOR_PATTERN = Pattern.compile("color:#([0-9a-fA-F]*)"); + + @Override + public CharSequence handleParagraph(FutabaChanParser parser, Theme theme, Post.Builder post, CharSequence text, Element element) { + return text; + } + + @Override + public CharSequence handleSpan(FutabaChanParser parser, Theme theme, Post.Builder post, Element span) { + SpannableString quote; + + Set classes = span.classNames(); + if (classes.contains("deadlink")) { + quote = new SpannableString(span.text()); + quote.setSpan(new ForegroundColorSpanHashed(theme.quoteColor), 0, quote.length(), 0); + quote.setSpan(new StrikethroughSpan(), 0, quote.length(), 0); + } else if (classes.contains("fortune")) { + // html looks like

Your fortune: + // manually add these
+ quote = new SpannableString("\n\n" + span.text()); + + String style = span.attr("style"); + if (!TextUtils.isEmpty(style)) { + style = style.replace(" ", ""); + + // private static final Pattern COLOR_PATTERN = Pattern.compile("color:#([0-9a-fA-F]*)"); + Matcher matcher = COLOR_PATTERN.matcher(style); + + int hexColor = 0xff0000; + if (matcher.find()) { + String group = matcher.group(1); + if (!TextUtils.isEmpty(group)) { + try { + hexColor = Integer.parseInt(group, 16); + } catch (NumberFormatException ignored) { + } + } + } + + if (hexColor >= 0 && hexColor <= 0xffffff) { + quote.setSpan(new ForegroundColorSpanHashed(0xff000000 + hexColor), 0, quote.length(), 0); + quote.setSpan(new StyleSpan(Typeface.BOLD), 0, quote.length(), 0); + } + } + } else if (classes.contains("abbr")) { + return null; + } else { + quote = new SpannableString(span.text()); + quote.setSpan(new ForegroundColorSpanHashed(theme.inlineQuoteColor), 0, quote.length(), 0); + parser.detectLinks(theme, post, span.text(), quote); + } + + return quote; + } + + @Override + public Link getLink(FutabaChanParser parser, Theme theme, Post.Builder post, Element anchor) { + String href = anchor.attr("href"); + Set classes = anchor.classNames(); + + PostLinkable.Type t = null; + String key = null; + Object value = null; + if (classes.contains("quotelink")) { + if (href.contains("/thread/")) { + // link to another thread + PostLinkable.ThreadLink threadLink = null; + + String[] slashSplit = href.split("/"); + if (slashSplit.length == 4) { + String board = slashSplit[1]; + String nums = slashSplit[3]; + String[] numsSplitted = nums.split("#p"); + if (numsSplitted.length == 2) { + try { + int tId = Integer.parseInt(numsSplitted[0]); + int pId = Integer.parseInt(numsSplitted[1]); + threadLink = new PostLinkable.ThreadLink(board, tId, pId); + } catch (NumberFormatException ignored) { + } + } + } + + if (threadLink != null) { + t = PostLinkable.Type.THREAD; + key = anchor.text(); + value = threadLink; + } + } else { + // normal quote + int id = -1; + + String[] splitted = href.split("#p"); + if (splitted.length == 2) { + try { + id = Integer.parseInt(splitted[1]); + } catch (NumberFormatException ignored) { + } + } + + if (id >= 0) { + t = PostLinkable.Type.QUOTE; + key = anchor.text(); + value = id; + } + } + } else { + // normal link + t = PostLinkable.Type.LINK; + key = anchor.text(); + value = href; + } + + if (t != null && key != null && value != null) { + Link link = new Link(); + link.type = t; + link.key = key; + link.value = value; + return link; + } else { + return null; + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java similarity index 73% rename from Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java rename to Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java index 943225e0..b9f71528 100644 --- a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParser.java @@ -15,19 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.floens.chan.chan; +package org.floens.chan.core.site.common; import android.graphics.Typeface; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.BackgroundColorSpan; -import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; import android.text.style.UnderlineSpan; -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; @@ -54,34 +52,23 @@ import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.inject.Inject; -import javax.inject.Singleton; import static org.floens.chan.utils.AndroidUtils.sp; -@Singleton -public class ChanParser { - private static final String TAG = "ChanParser"; - private static final Pattern COLOR_PATTERN = Pattern.compile("color:#([0-9a-fA-F]*)"); +public class FutabaChanParser implements ChanParser { + private static final String TAG = "FutabaChanParser"; private static final String SAVED_REPLY_SUFFIX = " (You)"; private static final String OP_REPLY_SUFFIX = " (OP)"; - @Inject - DatabaseManager databaseManager; - private final LinkExtractor linkExtractor = LinkExtractor.builder().linkTypes(EnumSet.of(LinkType.URL)).build(); - @Inject - public ChanParser() { - } + private FutabaChanParserHandler handler; - public Post parse(Post.Builder post) { - return parse(null, post); + public FutabaChanParser(FutabaChanParserHandler handler) { + this.handler = handler; } + @Override public Post parse(Theme theme, Post.Builder builder) { if (theme == null) { theme = ThemeHelper.getInstance().getTheme(); @@ -240,56 +227,30 @@ public class ChanParser { return spannable; } else { switch (node.nodeName()) { + case "p": { + List innerNodes = node.childNodes(); + List texts = new ArrayList<>(innerNodes.size() + 1); + + for (Node innerNode : innerNodes) { + CharSequence nodeParsed = parseNode(theme, post, innerNode); + if (nodeParsed != null) { + texts.add(nodeParsed); + } + } + + if (node.nextSibling() != null) { + texts.add("\n"); + } + + CharSequence res = TextUtils.concat(texts.toArray(new CharSequence[texts.size()])); + + return handler.handleParagraph(this, theme, post, res, (Element) node); + } case "br": { return "\n"; } case "span": { - Element span = (Element) node; - - SpannableString quote; - - Set classes = span.classNames(); - if (classes.contains("deadlink")) { - quote = new SpannableString(span.text()); - quote.setSpan(new ForegroundColorSpanHashed(theme.quoteColor), 0, quote.length(), 0); - quote.setSpan(new StrikethroughSpan(), 0, quote.length(), 0); - } else if (classes.contains("fortune")) { - // html looks like

Your fortune: - // manually add these
- quote = new SpannableString("\n\n" + span.text()); - - String style = span.attr("style"); - if (!TextUtils.isEmpty(style)) { - style = style.replace(" ", ""); - - // private static final Pattern COLOR_PATTERN = Pattern.compile("color:#([0-9a-fA-F]*)"); - Matcher matcher = COLOR_PATTERN.matcher(style); - - int hexColor = 0xff0000; - if (matcher.find()) { - String group = matcher.group(1); - if (!TextUtils.isEmpty(group)) { - try { - hexColor = Integer.parseInt(group, 16); - } catch (NumberFormatException ignored) { - } - } - } - - if (hexColor >= 0 && hexColor <= 0xffffff) { - quote.setSpan(new ForegroundColorSpanHashed(0xff000000 + hexColor), 0, quote.length(), 0); - quote.setSpan(new StyleSpan(Typeface.BOLD), 0, quote.length(), 0); - } - } - } else if (classes.contains("abbr")) { - return null; - } else { - quote = new SpannableString(span.text()); - quote.setSpan(new ForegroundColorSpanHashed(theme.inlineQuoteColor), 0, quote.length(), 0); - detectLinks(theme, post, span.text(), quote); - } - - return quote; + return handler.handleSpan(this, theme, post, (Element) node); } case "table": { Element table = (Element) node; @@ -383,78 +344,33 @@ public class ChanParser { } private CharSequence parseAnchor(Theme theme, Post.Builder post, Element anchor) { - String href = anchor.attr("href"); - Set classes = anchor.classNames(); - - PostLinkable.Type t = null; - String key = null; - Object value = null; - if (classes.contains("quotelink")) { - if (href.contains("/thread/")) { - // link to another thread - PostLinkable.ThreadLink threadLink = null; - - String[] slashSplit = href.split("/"); - if (slashSplit.length == 4) { - String board = slashSplit[1]; - String nums = slashSplit[3]; - String[] numsSplitted = nums.split("#p"); - if (numsSplitted.length == 2) { - try { - int tId = Integer.parseInt(numsSplitted[0]); - int pId = Integer.parseInt(numsSplitted[1]); - threadLink = new PostLinkable.ThreadLink(board, tId, pId); - } catch (NumberFormatException ignored) { - } - } - } + FutabaChanParserHandler.Link handlerLink = handler.getLink(this, theme, post, anchor); - if (threadLink != null) { - t = PostLinkable.Type.THREAD; - key = anchor.text() + " \u2192"; // arrow to the right - value = threadLink; - } - } else { - // normal quote - int id = -1; - - String[] splitted = href.split("#p"); - if (splitted.length == 2) { - try { - id = Integer.parseInt(splitted[1]); - } catch (NumberFormatException ignored) { - } - } + if (handlerLink != null) { + SpannableString link = new SpannableString(handlerLink.key); + PostLinkable pl = new PostLinkable(theme, handlerLink.key, handlerLink.value, handlerLink.type); + link.setSpan(pl, 0, link.length(), 0); + post.addLinkable(pl); - if (id >= 0) { - t = PostLinkable.Type.QUOTE; - key = anchor.text(); - value = id; - post.addReplyTo(id); + if (handlerLink.type == PostLinkable.Type.THREAD) { + handlerLink.key += " \u2192"; // arrow to the right + } - // Append OP when its a reply to OP - if (id == post.opId) { - key += OP_REPLY_SUFFIX; - } + if (handlerLink.type == PostLinkable.Type.QUOTE) { + int postNo = (int) handlerLink.value; + post.addReplyTo(postNo); - // Append You when it's a reply to an saved reply - if (databaseManager.getDatabaseSavedReplyManager().isSaved(post.board.code, id)) { - key += SAVED_REPLY_SUFFIX; - } + // Append OP when its a reply to OP + if (postNo == post.opId) { + handlerLink.key += OP_REPLY_SUFFIX; } - } - } else { - // normal link - t = PostLinkable.Type.LINK; - key = anchor.text(); - value = href; - } - if (t != null && key != null && value != null) { - SpannableString link = new SpannableString(key); - PostLinkable pl = new PostLinkable(theme, key, value, t); - link.setSpan(pl, 0, link.length(), 0); - post.addLinkable(pl); + // Append You when it's a reply to an saved reply + // TODO(multisite) + /*if (databaseManager.getDatabaseSavedReplyManager().isSaved(post.board.code, id)) { + key += SAVED_REPLY_SUFFIX; + }*/ + } return link; } else { @@ -462,10 +378,10 @@ public class ChanParser { } } - private void detectLinks(Theme theme, Post.Builder post, String text, SpannableString spannable) { + public void detectLinks(Theme theme, Post.Builder post, String text, SpannableString spannable) { // use autolink-java lib to detect links final Iterable links = linkExtractor.extractLinks(text); - for(final LinkSpan link : links) { + for (final LinkSpan link : links) { final String linkText = text.substring(link.getBeginIndex(), link.getEndIndex()); final PostLinkable pl = new PostLinkable(theme, linkText, linkText, PostLinkable.Type.LINK); spannable.setSpan(pl, link.getBeginIndex(), link.getEndIndex(), 0); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParserHandler.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParserHandler.java new file mode 100644 index 00000000..8743dd17 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanParserHandler.java @@ -0,0 +1,36 @@ +/* + * 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.site.common; + +import org.floens.chan.core.model.Post; +import org.floens.chan.core.model.PostLinkable; +import org.floens.chan.ui.theme.Theme; +import org.jsoup.nodes.Element; + +public interface FutabaChanParserHandler { + CharSequence handleParagraph(FutabaChanParser parser, Theme theme, Post.Builder post, CharSequence text, Element element); + + CharSequence handleSpan(FutabaChanParser parser, Theme theme, Post.Builder post, Element span); + + Link getLink(FutabaChanParser parser, Theme theme, Post.Builder post, Element anchor); + + class Link { + public PostLinkable.Type type; + public String key; + public Object value; + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanReader.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanReader.java index 0814fa12..0120179c 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanReader.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/FutabaChanReader.java @@ -15,6 +15,21 @@ import java.util.Map; import okhttp3.HttpUrl; public class FutabaChanReader implements ChanReader { + private final ChanParser chanParser; + + public FutabaChanReader() { + this.chanParser = new FutabaChanParser(new DefaultFutabaChanParserHandler()); + } + + public FutabaChanReader(ChanParser chanParser) { + this.chanParser = chanParser; + } + + @Override + public ChanParser getParser() { + return chanParser; + } + @Override public void loadThread(JsonReader reader, ChanReaderProcessingQueue queue) throws Exception { reader.beginObject(); diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java b/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java index ebc851c8..22e07769 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/common/PostParseCallable.java @@ -17,7 +17,6 @@ */ package org.floens.chan.core.site.common; -import org.floens.chan.chan.ChanParser; import org.floens.chan.core.database.DatabaseSavedReplyManager; import org.floens.chan.core.manager.FilterEngine; import org.floens.chan.core.model.orm.Filter; @@ -27,7 +26,7 @@ import java.util.List; import java.util.concurrent.Callable; // Called concurrently to parse the post html and the filters on it -// Belongs to ChanReaderRequest +// belong to ChanReaderRequest class PostParseCallable implements Callable { private static final String TAG = "PostParseCallable"; @@ -35,18 +34,18 @@ class PostParseCallable implements Callable { private List filters; private DatabaseSavedReplyManager savedReplyManager; private Post.Builder post; - private ChanParser parser; + private ChanReader reader; public PostParseCallable(FilterEngine filterEngine, List filters, DatabaseSavedReplyManager savedReplyManager, Post.Builder post, - ChanParser parser) { + ChanReader reader) { this.filterEngine = filterEngine; this.filters = filters; this.savedReplyManager = savedReplyManager; this.post = post; - this.parser = parser; + this.reader = reader; } @Override @@ -60,7 +59,7 @@ class PostParseCallable implements Callable { // Logger.e(TAG, "Incorrect data about post received for post " + post.no); // return null; // } - return parser.parse(post); + return reader.getParser().parse(null, post); } private void processPostFilter(Post.Builder post) { diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java index 56a94e85..72b2f102 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8.java @@ -33,6 +33,7 @@ import org.floens.chan.core.site.SiteEndpoints; import org.floens.chan.core.site.SiteIcon; import org.floens.chan.core.site.SiteRequestModifier; import org.floens.chan.core.site.common.ChanReader; +import org.floens.chan.core.site.common.FutabaChanParser; import org.floens.chan.core.site.common.FutabaChanReader; import org.floens.chan.core.site.http.DeleteRequest; import org.floens.chan.core.site.http.HttpCall; @@ -225,7 +226,8 @@ public class Chan8 extends SiteBase { @Override public ChanReader chanReader() { - return new FutabaChanReader(); + FutabaChanParser parser = new FutabaChanParser(new Chan8ParserHandler()); + return new FutabaChanReader(parser); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8ParserHandler.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8ParserHandler.java new file mode 100644 index 00000000..1cd47709 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan8/Chan8ParserHandler.java @@ -0,0 +1,133 @@ +/* + * 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.site.sites.chan8; + +import android.text.SpannableString; + +import org.floens.chan.core.model.Post; +import org.floens.chan.core.model.PostLinkable; +import org.floens.chan.core.site.common.DefaultFutabaChanParserHandler; +import org.floens.chan.core.site.common.FutabaChanParser; +import org.floens.chan.ui.span.ForegroundColorSpanHashed; +import org.floens.chan.ui.theme.Theme; +import org.jsoup.nodes.Element; + +import java.util.Set; + +public class Chan8ParserHandler extends DefaultFutabaChanParserHandler { + @Override + public CharSequence handleParagraph(FutabaChanParser parser, Theme theme, Post.Builder post, CharSequence text, Element element) { + if (element.hasClass("quote")) { + SpannableString quote = new SpannableString(text); + quote.setSpan(new ForegroundColorSpanHashed(theme.inlineQuoteColor), 0, quote.length(), 0); + parser.detectLinks(theme, post, quote.toString(), quote); + return quote; + } else { + return text; + } + } + + @Override + public CharSequence handleSpan(FutabaChanParser parser, Theme theme, Post.Builder post, Element span) { + SpannableString quote; + + Set classes = span.classNames(); + if (classes.contains("abbr")) { + return null; + } else if (classes.contains("spoiler")) { + quote = new SpannableString(span.text()); + PostLinkable pl = new PostLinkable(theme, span.text(), span.text(), PostLinkable.Type.SPOILER); + quote.setSpan(pl, 0, quote.length(), 0); + post.addLinkable(pl); + } else { + quote = new SpannableString(span.text()); + quote.setSpan(new ForegroundColorSpanHashed(theme.inlineQuoteColor), 0, quote.length(), 0); + parser.detectLinks(theme, post, span.text(), quote); + } + + return quote; + } + + @Override + public Link getLink(FutabaChanParser parser, Theme theme, Post.Builder post, Element anchor) { + String href = anchor.attr("href"); + + PostLinkable.Type t = null; + String key = null; + Object value = null; + if (href.startsWith("/")) { + if (href.contains("/thread/")) { + // link to another thread + PostLinkable.ThreadLink threadLink = null; + + String[] slashSplit = href.split("/"); + if (slashSplit.length == 4) { + String board = slashSplit[1]; + String nums = slashSplit[3]; + String[] numsSplitted = nums.split("#p"); + if (numsSplitted.length == 2) { + try { + int tId = Integer.parseInt(numsSplitted[0]); + int pId = Integer.parseInt(numsSplitted[1]); + threadLink = new PostLinkable.ThreadLink(board, tId, pId); + } catch (NumberFormatException ignored) { + } + } + } + + if (threadLink != null) { + t = PostLinkable.Type.THREAD; + key = anchor.text(); + value = threadLink; + } + } else { + // normal quote + int id = -1; + + String[] splitted = href.split("#"); + if (splitted.length == 2) { + try { + id = Integer.parseInt(splitted[1]); + } catch (NumberFormatException ignored) { + } + } + + if (id >= 0) { + t = PostLinkable.Type.QUOTE; + key = anchor.text(); + value = id; + } + } + } else { + // normal link + t = PostLinkable.Type.LINK; + key = anchor.text(); + value = href; + } + + if (t != null && key != null && value != null) { + Link link = new Link(); + link.type = t; + link.key = key; + link.value = value; + return link; + } else { + return null; + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java index 830aaacf..fc4bf8b5 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java @@ -20,7 +20,6 @@ package org.floens.chan.ui.activity; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; -import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.nfc.NfcEvent; @@ -35,7 +34,6 @@ import android.view.ViewGroup; import org.floens.chan.Chan; import org.floens.chan.R; -import org.floens.chan.chan.ChanHelper; import org.floens.chan.controller.Controller; import org.floens.chan.controller.NavigationController; import org.floens.chan.core.database.DatabaseLoadableManager; @@ -135,7 +133,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat private void setupFromStateOrFreshLaunch(Bundle savedInstanceState) { boolean loadDefault = true; - if (savedInstanceState != null) { + /*if (savedInstanceState != null) { // Restore the activity state from the previously saved state. ChanState chanState = savedInstanceState.getParcelable(STATE_KEY); if (chanState == null) { @@ -177,7 +175,7 @@ public class StartActivity extends AppCompatActivity implements NfcAdapter.Creat .show(); } } - } + }*/ // Not from a state or from an url, launch the setup controller if no boards are setup up yet, // otherwise load the default saved board. diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java index 0309d8ad..598e7c12 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/SiteSetupController.java @@ -58,10 +58,11 @@ public class SiteSetupController extends SettingsController implements SiteSetup // Preferences populatePreferences(); - buildPreferences(); // Presenter presenter.create(this, site); + + buildPreferences(); } public void setSite(Site site) { 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 848c53aa..18385105 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 @@ -37,7 +37,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.floens.chan.R; -import org.floens.chan.chan.ChanParser; +import org.floens.chan.core.site.common.DefaultFutabaChanParserHandler; +import org.floens.chan.core.site.common.FutabaChanParser; import org.floens.chan.controller.Controller; import org.floens.chan.core.model.orm.Board; import org.floens.chan.core.model.orm.Loadable; @@ -250,7 +251,7 @@ public class ThemeSettingsController extends Controller implements View.OnClickL "http://example.com/" + "
" + "Phasellus consequat semper sodales. Donec dolor lectus, aliquet nec mollis vel, rutrum vel enim."); - Post post = getGraph().get(ChanParser.class).parse(theme, builder); + Post post = new FutabaChanParser(new DefaultFutabaChanParserHandler()).parse(theme, builder); LinearLayout linearLayout = new LinearLayout(themeContext); linearLayout.setOrientation(LinearLayout.VERTICAL); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java index 51104bf7..c2aa91b6 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/settings/SettingsController.java @@ -168,7 +168,10 @@ public class SettingsController extends Controller implements AndroidUtils.OnMea bottom.setText(bottomText); } - AnimationUtils.animateHeight(bottom, bottomText != null, ((View) view.getParent()).getWidth()); + // This way of animating never works on textviews if they're just added. + if (bottom.getHeight() != 0) { + AnimationUtils.animateHeight(bottom, bottomText != null, ((View) view.getParent()).getWidth()); + } } else { bottom.setText(bottomText); bottom.setVisibility(bottomText == null ? View.GONE : View.VISIBLE); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/theme/Theme.java b/Clover/app/src/main/java/org/floens/chan/ui/theme/Theme.java index b7223539..b3343e5a 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/theme/Theme.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/theme/Theme.java @@ -30,7 +30,7 @@ import org.floens.chan.utils.AndroidUtils; /** * A Theme
- * Used for setting the toolbar color, and passed around {@link org.floens.chan.chan.ChanParser} to give the spans the correct color.
+ * Used for setting the toolbar color, and passed around {@link org.floens.chan.core.site.common.ChanParser} to give the spans the correct color.
* Technically should the parser not do UI, but it is important that the spans do not get created on an UI thread for performance. */ public class Theme {