From 87ab68217dcc5ca419b2a96a37bec27edbb8fdb8 Mon Sep 17 00:00:00 2001 From: scria1000 <91804886+scria1000@users.noreply.github.com> Date: Thu, 9 Dec 2021 14:54:25 +0300 Subject: Some more spoiler parsing optimizations Don't bother trying to parse a text if it doesn't have spoiler opening. --- .../activities/CommentActivity.java | 8 +++- .../infinityforreddit/markdown/SpoilerOpening.java | 21 +++++++++ .../markdown/SpoilerOpeningParser.java | 27 +++++++++++ .../markdown/SpoilerParserPlugin.java | 52 ++++++++++++++++------ 4 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpening.java create mode 100644 app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpeningParser.java (limited to 'app/src/main/java/ml') diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java index 4a06c3a7..a9275779 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/CommentActivity.java @@ -70,6 +70,7 @@ import ml.docilealligator.infinityforreddit.comment.SendComment; import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper; import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFixed; import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent; +import ml.docilealligator.infinityforreddit.markdown.SpoilerParserPlugin; import ml.docilealligator.infinityforreddit.markdown.SuperscriptPlugin; import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils; import ml.docilealligator.infinityforreddit.utils.Utils; @@ -134,6 +135,8 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA private Uri capturedImageUri; private ArrayList uploadedImages = new ArrayList<>(); private Menu mMenu; + private int commentColor; + private int commentSpoilerBackgroundColor; @Override protected void onCreate(Bundle savedInstanceState) { @@ -192,6 +195,7 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA builder.linkColor(linkColor); } }) + .usePlugin(SpoilerParserPlugin.create(commentColor, commentSpoilerBackgroundColor)) .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS)) .build(); if (parentTextMarkdown != null) { @@ -337,7 +341,9 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA protected void applyCustomTheme() { coordinatorLayout.setBackgroundColor(mCustomThemeWrapper.getBackgroundColor()); applyAppBarLayoutAndCollapsingToolbarLayoutAndToolbarTheme(appBarLayout, null, toolbar); - commentParentMarkwonView.setTextColor(mCustomThemeWrapper.getCommentColor()); + commentColor = mCustomThemeWrapper.getCommentColor(); + commentSpoilerBackgroundColor = commentColor | 0xFF000000; + commentParentMarkwonView.setTextColor(commentColor); divider.setBackgroundColor(mCustomThemeWrapper.getDividerColor()); commentEditText.setTextColor(mCustomThemeWrapper.getCommentColor()); int secondaryTextColor = mCustomThemeWrapper.getSecondaryTextColor(); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpening.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpening.java new file mode 100644 index 00000000..279cba65 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpening.java @@ -0,0 +1,21 @@ +package ml.docilealligator.infinityforreddit.markdown; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Visitor; + +class SpoilerOpening extends CustomNode { + private String literal; + + @Override + public void accept(Visitor visitor) { + visitor.visit(this); + } + + public String getLiteral() { + return literal; + } + + public void setLiteral(String literal) { + this.literal = literal; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpeningParser.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpeningParser.java new file mode 100644 index 00000000..391e4a88 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerOpeningParser.java @@ -0,0 +1,27 @@ +package ml.docilealligator.infinityforreddit.markdown; + +import androidx.annotation.Nullable; + +import org.commonmark.node.Node; + +import io.noties.markwon.inlineparser.InlineProcessor; + +public class SpoilerOpeningParser extends InlineProcessor { + @Override + public char specialCharacter() { + return '>'; + } + + @Nullable + @Override + protected Node parse() { + index++; + if (peek() == '!') { + index++; + SpoilerOpening node = new SpoilerOpening(); + node.setLiteral(">!"); + return node; + } + return null; + } +} diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java index 3a05b71c..85dc2be5 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/markdown/SpoilerParserPlugin.java @@ -11,7 +11,6 @@ import androidx.annotation.NonNull; import org.commonmark.node.Block; import org.commonmark.node.BlockQuote; import org.commonmark.node.HtmlBlock; -import org.commonmark.node.HtmlInline; import org.commonmark.parser.Parser; import java.util.ArrayList; @@ -19,13 +18,17 @@ import java.util.Set; import java.util.Stack; import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.MarkwonVisitor; import io.noties.markwon.core.CorePlugin; import io.noties.markwon.core.spans.CodeBlockSpan; import io.noties.markwon.core.spans.CodeSpan; +import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; public class SpoilerParserPlugin extends AbstractMarkwonPlugin { private final int textColor; private final int backgroundColor; + private boolean textHasSpoiler = false; + private int firstSpoilerStart = -1; SpoilerParserPlugin(int textColor, int backgroundColor) { this.textColor = textColor; @@ -36,13 +39,30 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { return new SpoilerParserPlugin(textColor, backgroundColor); } + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder.on(SpoilerOpening.class, (visitor, opening) -> { + textHasSpoiler = true; + if (firstSpoilerStart == -1) { + firstSpoilerStart = visitor.length(); + } + visitor.builder().append(opening.getLiteral()); + }); + } + + @Override + public void configure(@NonNull Registry registry) { + registry.require(MarkwonInlineParserPlugin.class, plugin -> + plugin.factoryBuilder().addInlineProcessor(new SpoilerOpeningParser()) + ); + } + @Override public void configureParser(@NonNull Parser.Builder builder) { builder.customBlockParserFactory(new BlockQuoteWithExceptionParser.Factory()); Set> blocks = CorePlugin.enabledBlockTypes(); blocks.remove(HtmlBlock.class); - blocks.remove(HtmlInline.class); blocks.remove(BlockQuote.class); builder.enabledBlockTypes(blocks); @@ -50,16 +70,19 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { @Override public void afterSetText(@NonNull TextView textView) { - textView.setHighlightColor(Color.TRANSPARENT); - - if (textView.getText().length() < 5) { + if (!textHasSpoiler || textView.getText().length() < 5) { + firstSpoilerStart = 0; return; } + textView.setHighlightColor(Color.TRANSPARENT); + SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText()); - ArrayList> spoilers = parse(markdownStringBuilder); + ArrayList> spoilers = parse(markdownStringBuilder, firstSpoilerStart); + firstSpoilerStart = 0; if (spoilers.size() == 0) { + textHasSpoiler = false; return; } @@ -118,31 +141,32 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin { // Don't allow more than one new line after every non-blank line // Try not to care about recursing spoilers, we just want the outermost spoiler because // spoiler revealing-hiding breaks with recursing spoilers - private ArrayList> parse(SpannableStringBuilder markdown) { + private ArrayList> parse(SpannableStringBuilder markdown, int start) { final int MAX_NEW_LINE = 1; int length = markdown.length(); Stack openSpoilerStack = new Stack<>(); ArrayList> closedSpoilers = new ArrayList<>(); int new_lines = 0; - for (int i = 0; i < length; i++) { - if (markdown.charAt(i) == '\n') { + for (int i = start; i < length; i++) { + char currentChar = markdown.charAt(i); + if (currentChar == '\n') { new_lines++; if (new_lines > MAX_NEW_LINE) { openSpoilerStack.clear(); new_lines = 0; } - } else if ((markdown.charAt(i) != '>') - && (markdown.charAt(i) != '<') - && (markdown.charAt(i) != '!')) { + } else if ((currentChar != '>') + && (currentChar != '<') + && (currentChar != '!')) { new_lines = 0; } else if ((i + 1 < length) - && markdown.charAt(i) == '>' + && currentChar == '>' && markdown.charAt(i + 1) == '!') { openSpoilerStack.push(i + 2); } else if ((i + 1 < length) && (i - 1 >= 0) && openSpoilerStack.size() > 0 && markdown.charAt(i - 1) != '>' - && markdown.charAt(i) == '!' + && currentChar == '!' && markdown.charAt(i + 1) == '<') { var pos = openSpoilerStack.pop(); if (!closedSpoilers.isEmpty() -- cgit v1.2.3