From 4f827b15537f92b334db39f63f77d82cfb7949a2 Mon Sep 17 00:00:00 2001 From: Floens Date: Mon, 1 Jun 2015 19:43:13 +0200 Subject: [PATCH] Let ChanParser get the colors from a Theme object Resolve the attributes manually --- .../java/org/floens/chan/chan/ChanParser.java | 80 +++++++------------ .../java/org/floens/chan/core/model/Post.java | 2 +- .../floens/chan/core/model/PostLinkable.java | 24 +++--- .../org/floens/chan/test/TestActivity.java | 8 +- .../chan/ui/activity/StartActivity.java | 4 +- .../org/floens/chan/ui/cell/PostCell.java | 4 + .../controller/ThemeSettingsController.java | 2 +- .../java/org/floens/chan/ui/theme/Theme.java | 56 +++++++++++++ .../org/floens/chan/ui/theme/ThemeHelper.java | 65 +-------------- Clover/app/src/main/res/values/styles.xml | 1 - 10 files changed, 110 insertions(+), 136 deletions(-) diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java b/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java index feef5cb9..397acb6d 100644 --- a/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java +++ b/Clover/app/src/main/java/org/floens/chan/chan/ChanParser.java @@ -18,8 +18,6 @@ package org.floens.chan.chan; -import android.content.Context; -import android.content.res.TypedArray; import android.graphics.Typeface; import android.text.SpannableString; import android.text.TextUtils; @@ -32,12 +30,11 @@ import android.text.style.TypefaceSpan; import android.text.style.UnderlineSpan; import org.floens.chan.Chan; -import org.floens.chan.R; 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.ui.theme.Theme; import org.floens.chan.ui.theme.ThemeHelper; -import org.floens.chan.utils.AndroidUtils; import org.floens.chan.utils.Logger; import org.jsoup.Jsoup; import org.jsoup.helper.StringUtil; @@ -68,16 +65,13 @@ public class ChanParser { return instance; } - public ChanParser() { + public void parse(Post post) { + parse(null, post); } - public void parse(Context context, Post post) { - if (context == null) { - context = ThemeHelper.getInstance().getThemedContext(); - } - - if (context == null) { - context = AndroidUtils.getAppRes(); + public void parse(Theme theme, Post post) { + if (theme == null) { + theme = ThemeHelper.getInstance().getTheme(); } try { @@ -94,15 +88,15 @@ public class ChanParser { if (!post.parsedSpans) { post.parsedSpans = true; - parseSpans(context, post); + parseSpans(theme, post); } if (post.rawComment != null) { - post.comment = parseComment(post, post.rawComment); + post.comment = parseComment(theme, post, post.rawComment); } } - private void parseSpans(Context context, Post post) { + private void parseSpans(Theme theme, Post post) { boolean anonymize = ChanSettings.anonymize.get(); boolean anonymizeIds = ChanSettings.anonymizeIds.get(); @@ -117,35 +111,19 @@ public class ChanParser { int detailsSizePx = sp(Integer.parseInt(ChanSettings.fontSize.get()) - 4); - TypedArray ta = context.obtainStyledAttributes(new int[]{ - R.attr.post_subject_color, - R.attr.post_name_color, - R.attr.post_id_background_light, - R.attr.post_id_background_dark, - R.attr.post_capcode_color - }); - - int subjectColor = ta.getColor(0, 0); - int nameColor = ta.getColor(1, 0); - int idBackgroundLight = ta.getColor(2, 0); - int idBackgroundDark = ta.getColor(3, 0); - int capcodeColor = ta.getColor(4, 0); - - ta.recycle(); - if (!TextUtils.isEmpty(post.subject)) { post.subjectSpan = new SpannableString(post.subject); - post.subjectSpan.setSpan(new ForegroundColorSpan(subjectColor), 0, post.subjectSpan.length(), 0); + 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); - post.nameSpan.setSpan(new ForegroundColorSpan(nameColor), 0, post.nameSpan.length(), 0); + post.nameSpan.setSpan(new ForegroundColorSpan(theme.nameColor), 0, post.nameSpan.length(), 0); } if (!TextUtils.isEmpty(post.tripcode)) { post.tripcodeSpan = new SpannableString(post.tripcode); - post.tripcodeSpan.setSpan(new ForegroundColorSpan(nameColor), 0, post.tripcodeSpan.length(), 0); + post.tripcodeSpan.setSpan(new ForegroundColorSpan(theme.nameColor), 0, post.tripcodeSpan.length(), 0); post.tripcodeSpan.setSpan(new AbsoluteSizeSpan(detailsSizePx), 0, post.tripcodeSpan.length(), 0); } @@ -161,7 +139,7 @@ public class ChanParser { int idColor = (0xff << 24) + (r << 16) + (g << 8) + b; boolean lightColor = (r * 0.299f) + (g * 0.587f) + (b * 0.114f) > 125f; - int idBgColor = lightColor ? idBackgroundLight : idBackgroundDark; + int idBgColor = lightColor ? theme.idBackgroundLight : theme.idBackgroundDark; post.idSpan.setSpan(new ForegroundColorSpan(idColor), 0, post.idSpan.length(), 0); post.idSpan.setSpan(new BackgroundColorSpan(idBgColor), 0, post.idSpan.length(), 0); @@ -170,7 +148,7 @@ public class ChanParser { if (!TextUtils.isEmpty(post.capcode)) { post.capcodeSpan = new SpannableString("Capcode: " + post.capcode); - post.capcodeSpan.setSpan(new ForegroundColorSpan(capcodeColor), 0, post.capcodeSpan.length(), 0); + post.capcodeSpan.setSpan(new ForegroundColorSpan(theme.capcodeColor), 0, post.capcodeSpan.length(), 0); post.capcodeSpan.setSpan(new AbsoluteSizeSpan(detailsSizePx), 0, post.capcodeSpan.length(), 0); } @@ -192,7 +170,7 @@ public class ChanParser { } } - private CharSequence parseComment(Post post, String commentRaw) { + private CharSequence parseComment(Theme theme, Post post, String commentRaw) { CharSequence total = new SpannableString(""); try { @@ -204,7 +182,7 @@ public class ChanParser { List texts = new ArrayList<>(nodes.size()); for (Node node : nodes) { - CharSequence nodeParsed = parseNode(post, node); + CharSequence nodeParsed = parseNode(theme, post, node); if (nodeParsed != null) { texts.add(nodeParsed); } @@ -218,12 +196,12 @@ public class ChanParser { return total; } - private CharSequence parseNode(Post post, Node node) { + private CharSequence parseNode(Theme theme, Post post, Node node) { if (node instanceof TextNode) { String text = ((TextNode) node).text(); SpannableString spannable = new SpannableString(text); - detectLinks(post, text, spannable); + detectLinks(theme, post, text, spannable); return spannable; } else { @@ -239,7 +217,7 @@ public class ChanParser { Set classes = span.classNames(); if (classes.contains("deadlink")) { quote = new SpannableString(span.text()); - quote.setSpan(new ForegroundColorSpan(ThemeHelper.getInstance().getQuoteColor()), 0, quote.length(), 0); + quote.setSpan(new ForegroundColorSpan(theme.quoteColor), 0, quote.length(), 0); quote.setSpan(new StrikethroughSpan(), 0, quote.length(), 0); } else if (classes.contains("fortune")) { // html looks like

Your fortune: @@ -273,8 +251,8 @@ public class ChanParser { return null; } else { quote = new SpannableString(span.text()); - quote.setSpan(new ForegroundColorSpan(ThemeHelper.getInstance().getInlineQuoteColor()), 0, quote.length(), 0); - detectLinks(post, span.text(), quote); + quote.setSpan(new ForegroundColorSpan(theme.inlineQuoteColor), 0, quote.length(), 0); + detectLinks(theme, post, span.text(), quote); } return quote; @@ -311,7 +289,7 @@ public class ChanParser { } SpannableString tableTotal = new SpannableString(TextUtils.concat(parts.toArray(new CharSequence[parts.size()]))); - tableTotal.setSpan(new ForegroundColorSpan(ThemeHelper.getInstance().getInlineQuoteColor()), 0, tableTotal.length(), 0); + tableTotal.setSpan(new ForegroundColorSpan(theme.inlineQuoteColor), 0, tableTotal.length(), 0); tableTotal.setSpan(new AbsoluteSizeSpan(sp(12f)), 0, tableTotal.length(), 0); return tableTotal; @@ -320,13 +298,13 @@ public class ChanParser { Element strong = (Element) node; SpannableString red = new SpannableString(strong.text()); - red.setSpan(new ForegroundColorSpan(ThemeHelper.getInstance().getQuoteColor()), 0, red.length(), 0); + red.setSpan(new ForegroundColorSpan(theme.quoteColor), 0, red.length(), 0); red.setSpan(new StyleSpan(Typeface.BOLD), 0, red.length(), 0); return red; } case "a": { - CharSequence anchor = parseAnchor(post, (Element) node); + CharSequence anchor = parseAnchor(theme, post, (Element) node); if (anchor != null) { return anchor; } else { @@ -338,7 +316,7 @@ public class ChanParser { SpannableString link = new SpannableString(spoiler.text()); - PostLinkable pl = new PostLinkable(post, spoiler.text(), spoiler.text(), PostLinkable.Type.SPOILER); + PostLinkable pl = new PostLinkable(theme, post, spoiler.text(), spoiler.text(), PostLinkable.Type.SPOILER); link.setSpan(pl, 0, link.length(), 0); post.linkables.add(pl); @@ -370,7 +348,7 @@ public class ChanParser { } } - private CharSequence parseAnchor(Post post, Element anchor) { + private CharSequence parseAnchor(Theme theme, Post post, Element anchor) { String href = anchor.attr("href"); Set classes = anchor.classNames(); @@ -441,7 +419,7 @@ public class ChanParser { if (t != null && key != null && value != null) { SpannableString link = new SpannableString(key); - PostLinkable pl = new PostLinkable(post, key, value, t); + PostLinkable pl = new PostLinkable(theme, post, key, value, t); link.setSpan(pl, 0, link.length(), 0); post.linkables.add(pl); @@ -451,7 +429,7 @@ public class ChanParser { } } - private void detectLinks(Post post, String text, SpannableString spannable) { + private void detectLinks(Theme theme, Post post, String text, SpannableString spannable) { int startPos = 0; int endPos; while (true) { @@ -474,7 +452,7 @@ public class ChanParser { String linkString = text.substring(startPos, endPos); - PostLinkable pl = new PostLinkable(post, linkString, linkString, PostLinkable.Type.LINK); + PostLinkable pl = new PostLinkable(theme, post, linkString, linkString, PostLinkable.Type.LINK); spannable.setSpan(pl, startPos, endPos, 0); post.linkables.add(pl); 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 3638f7b6..b6d59a8b 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 @@ -133,7 +133,7 @@ public class Post { countryUrl = b.trollFlags ? ChanUrls.getTrollCountryFlagUrl(country) : ChanUrls.getCountryFlagUrl(country); } - ChanParser.getInstance().parse(null, this); + ChanParser.getInstance().parse(this); return true; } diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/PostLinkable.java b/Clover/app/src/main/java/org/floens/chan/core/model/PostLinkable.java index e95f627c..4e756676 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/PostLinkable.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/PostLinkable.java @@ -22,19 +22,24 @@ import android.text.TextPaint; import android.text.style.ClickableSpan; import android.view.View; -import org.floens.chan.ui.theme.ThemeHelper; +import org.floens.chan.ui.cell.PostCell; +import org.floens.chan.ui.theme.Theme; import java.util.ArrayList; import java.util.List; /** - * Anything that links to something in a post uses this entity. + * A Clickable span that handles post clicks. These are created in ChanParser for post quotes, spoilers etc.
+ * PostCells bind callbacks with addCallback and call removeCallback when done.
+ * PostCell has a {@link PostCell.PostViewMovementMethod}, that searches spans at the location the TextView was tapped, + * and handled if it was a PostLinkable. */ public class PostLinkable extends ClickableSpan { public enum Type { QUOTE, LINK, SPOILER, THREAD } + public final Theme theme; public final Post post; public final String key; public final Object value; @@ -43,7 +48,8 @@ public class PostLinkable extends ClickableSpan { private List callbacks = new ArrayList<>(); private boolean spoilerVisible = false; - public PostLinkable(Post post, String key, Object value, Type type) { + public PostLinkable(Theme theme, Post post, String key, Object value, Type type) { + this.theme = theme; this.post = post; this.key = key; this.value = value; @@ -77,21 +83,21 @@ public class PostLinkable extends ClickableSpan { if (type == Type.QUOTE) { Callback top = topCallback(); if (value instanceof Integer && top != null && (Integer) value == top.getMarkedNo(this)) { - ds.setColor(ThemeHelper.getInstance().getHighlightQuoteColor()); + ds.setColor(theme.highlightQuoteColor); } else { - ds.setColor(ThemeHelper.getInstance().getQuoteColor()); + ds.setColor(theme.quoteColor); } } else if (type == Type.LINK) { - ds.setColor(ThemeHelper.getInstance().getLinkColor()); + ds.setColor(theme.linkColor); } else { - ds.setColor(ThemeHelper.getInstance().getQuoteColor()); + ds.setColor(theme.quoteColor); } ds.setUnderlineText(true); } else if (type == Type.SPOILER) { if (!spoilerVisible) { - ds.setColor(ThemeHelper.getInstance().getSpoilerColor()); - ds.bgColor = ThemeHelper.getInstance().getSpoilerColor(); + ds.setColor(theme.spoilerColor); + ds.bgColor = theme.spoilerColor; ds.setUnderlineText(false); } } diff --git a/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java b/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java index 631eb241..632a8f5b 100644 --- a/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/test/TestActivity.java @@ -56,7 +56,7 @@ public class TestActivity extends Activity implements View.OnClickListener { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ThemeHelper.getInstance().addContext(this); + ThemeHelper.getInstance().setupContext(this); LinearLayout linearLayout = new LinearLayout(this); linearLayout.setOrientation(LinearLayout.VERTICAL); @@ -93,12 +93,6 @@ public class TestActivity extends Activity implements View.OnClickListener { fileCache = new FileCache(fileCacheDir, 50 * 1024 * 1024, Chan.getInstance().getUserAgent()); } - @Override - protected void onDestroy() { - super.onDestroy(); - ThemeHelper.getInstance().removeContext(this); - } - @Override public void onClick(View v) { if (v == clearCache) { 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 e76119a9..05306be3 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 @@ -58,7 +58,7 @@ public class StartActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - ThemeHelper.getInstance().addContext(this); + ThemeHelper.getInstance().setupContext(this); contentView = (ViewGroup) findViewById(android.R.id.content); @@ -211,8 +211,6 @@ public class StartActivity extends AppCompatActivity { stackTop().onDestroy(); stack.clear(); - - ThemeHelper.getInstance().removeContext(this); } @Override 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 4cf41724..f92b01e6 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 @@ -449,6 +449,10 @@ public class PostCell extends RelativeLayout implements PostLinkable.Callback { private static BackgroundColorSpan BACKGROUND_SPAN = new BackgroundColorSpan(0x6633B5E5); + /** + * A MovementMethod that searches for PostLinkables.
+ * See {@link PostLinkable} for more information. + */ private class PostViewMovementMethod extends LinkMovementMethod { @Override public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { 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 7668d489..a8963f99 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 @@ -182,7 +182,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."; - ChanParser.getInstance().parse(themeContext, post); + ChanParser.getInstance().parse(theme, post); LinearLayout linearLayout = new LinearLayout(themeContext); linearLayout.setOrientation(LinearLayout.VERTICAL); 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 e02751fb..8a728f97 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 @@ -17,6 +17,17 @@ */ package org.floens.chan.ui.theme; +import android.content.res.Resources; +import android.content.res.TypedArray; + +import org.floens.chan.R; +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.
+ * 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 { public final String displayName; public final String name; @@ -24,11 +35,56 @@ public class Theme { public final boolean isLightTheme; public final ThemeHelper.PrimaryColor primaryColor; + public int quoteColor; + public int highlightQuoteColor; + public int linkColor; + public int spoilerColor; + public int inlineQuoteColor; + public int subjectColor; + public int nameColor; + public int idBackgroundLight; + public int idBackgroundDark; + public int capcodeColor; + public Theme(String displayName, String name, int resValue, boolean isLightTheme, ThemeHelper.PrimaryColor primaryColor) { this.displayName = displayName; this.name = name; this.resValue = resValue; this.isLightTheme = isLightTheme; this.primaryColor = primaryColor; + + resolveSpanColors(); + } + + private void resolveSpanColors() { + Resources.Theme theme = AndroidUtils.getAppRes().getResources().newTheme(); + theme.applyStyle(R.style.Chan_Theme, true); + theme.applyStyle(resValue, true); + + TypedArray ta = theme.obtainStyledAttributes(new int[]{ + R.attr.post_quote_color, + R.attr.post_highlight_quote_color, + R.attr.post_link_color, + R.attr.post_spoiler_color, + R.attr.post_inline_quote_color, + R.attr.post_subject_color, + R.attr.post_name_color, + R.attr.post_id_background_light, + R.attr.post_id_background_dark, + R.attr.post_capcode_color + }); + + quoteColor = ta.getColor(0, 0); + highlightQuoteColor = ta.getColor(1, 0); + linkColor = ta.getColor(2, 0); + spoilerColor = ta.getColor(3, 0); + inlineQuoteColor = ta.getColor(4, 0); + subjectColor = ta.getColor(5, 0); + nameColor = ta.getColor(6, 0); + idBackgroundLight = ta.getColor(7, 0); + idBackgroundDark = ta.getColor(8, 0); + capcodeColor = ta.getColor(9, 0); + + ta.recycle(); } } diff --git a/Clover/app/src/main/java/org/floens/chan/ui/theme/ThemeHelper.java b/Clover/app/src/main/java/org/floens/chan/ui/theme/ThemeHelper.java index ca889213..b2bb23b5 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/theme/ThemeHelper.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/theme/ThemeHelper.java @@ -19,8 +19,6 @@ package org.floens.chan.ui.theme; import android.app.Activity; import android.app.ActivityManager; -import android.content.Context; -import android.content.res.TypedArray; import android.os.Build; import org.floens.chan.R; @@ -39,22 +37,15 @@ public class ThemeHelper { return instance; } - private List contexts = new ArrayList<>(); - private List themes = new ArrayList<>(); private Theme theme; - private int quoteColor; - private int highlightQuoteColor; - private int linkColor; - private int spoilerColor; - private int inlineQuoteColor; - public ThemeHelper() { themes.add(new Theme("Light", "light", R.style.Chan_Theme, true, PrimaryColor.GREEN)); themes.add(new Theme("Dark", "dark", R.style.Chan_Theme_Dark, false, PrimaryColor.DARK)); themes.add(new Theme("Black", "black", R.style.Chan_Theme_Black, false, PrimaryColor.BLACK)); + updateCurrentTheme(); } public List getThemes() { @@ -78,67 +69,15 @@ public class ThemeHelper { return theme; } - public Context getThemedContext() { - return contexts.size() > 0 ? contexts.get(contexts.size() - 1) : null; - } - - public void addContext(Activity context) { - if (contexts.contains(context)) { - Logger.e(TAG, "addContext: context already added"); - } else { - contexts.add(context); - } - + public void setupContext(Activity context) { updateCurrentTheme(); context.setTheme(theme.resValue); - TypedArray ta = context.obtainStyledAttributes(new int[]{ - R.attr.post_quote_color, - R.attr.post_highlight_quote_color, - R.attr.post_link_color, - R.attr.post_spoiler_color, - R.attr.post_inline_quote_color - }); - - quoteColor = ta.getColor(0, 0); - highlightQuoteColor = ta.getColor(1, 0); - linkColor = ta.getColor(2, 0); - spoilerColor = ta.getColor(3, 0); - inlineQuoteColor = ta.getColor(4, 0); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { context.getWindow().setStatusBarColor(theme.primaryColor.dark); context.getWindow().setNavigationBarColor(0xff000000); context.setTaskDescription(new ActivityManager.TaskDescription(null, null, theme.primaryColor.color)); } - - ta.recycle(); - } - - public void removeContext(Activity context) { - if (!contexts.remove(context)) { - Logger.e(TAG, "removeContext: context not found"); - } - } - - public int getQuoteColor() { - return quoteColor; - } - - public int getHighlightQuoteColor() { - return highlightQuoteColor; - } - - public int getLinkColor() { - return linkColor; - } - - public int getSpoilerColor() { - return spoilerColor; - } - - public int getInlineQuoteColor() { - return inlineQuoteColor; } public enum PrimaryColor { diff --git a/Clover/app/src/main/res/values/styles.xml b/Clover/app/src/main/res/values/styles.xml index 8e2fe846..84d82c71 100644 --- a/Clover/app/src/main/res/values/styles.xml +++ b/Clover/app/src/main/res/values/styles.xml @@ -76,7 +76,6 @@ along with this program. If not, see . #b2ffffff #4cffffff - #1effffff #ff5C5C5C