mirror of
https://codeberg.org/Bazsalanszky/Infinity-For-Lemmy.git
synced 2024-12-28 11:58:23 +01:00
Add a non-regex solution for parsing spoilers
Add a non-regex solution for parsing spoilers that can also handle code blocks Add a custom BlockQuoteParser to prevent spoilers from being consumed as block quotes without the need for html escaping Make revealed spoiler backgrounds slightly darker
This commit is contained in:
parent
ea1501b5a4
commit
b0134984ca
@ -132,7 +132,7 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
|
|||||||
|
|
||||||
mFullName = getIntent().getStringExtra(EXTRA_FULLNAME);
|
mFullName = getIntent().getStringExtra(EXTRA_FULLNAME);
|
||||||
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
|
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
|
||||||
mCommentContent = getIntent().getStringExtra(EXTRA_CONTENT).replaceAll(">!",">!");
|
mCommentContent = getIntent().getStringExtra(EXTRA_CONTENT);
|
||||||
contentEditText.setText(mCommentContent);
|
contentEditText.setText(mCommentContent);
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
|
@ -141,7 +141,7 @@ public class EditPostActivity extends BaseActivity implements UploadImageEnabled
|
|||||||
mFullName = getIntent().getStringExtra(EXTRA_FULLNAME);
|
mFullName = getIntent().getStringExtra(EXTRA_FULLNAME);
|
||||||
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
|
mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
|
||||||
titleTextView.setText(getIntent().getStringExtra(EXTRA_TITLE));
|
titleTextView.setText(getIntent().getStringExtra(EXTRA_TITLE));
|
||||||
mPostContent = getIntent().getStringExtra(EXTRA_CONTENT).replaceAll(">!",">!");;
|
mPostContent = getIntent().getStringExtra(EXTRA_CONTENT);
|
||||||
contentEditText.setText(mPostContent);
|
contentEditText.setText(mPostContent);
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
|
@ -9,8 +9,6 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.text.SpannableStringBuilder;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.util.Linkify;
|
import android.text.util.Linkify;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -36,8 +34,6 @@ import com.lsjwzh.widget.materialloadingprogressbar.CircleProgressBar;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -48,6 +44,7 @@ import io.noties.markwon.core.MarkwonTheme;
|
|||||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||||
import io.noties.markwon.html.HtmlPlugin;
|
import io.noties.markwon.html.HtmlPlugin;
|
||||||
import io.noties.markwon.html.tag.SuperScriptHandler;
|
import io.noties.markwon.html.tag.SuperScriptHandler;
|
||||||
|
import io.noties.markwon.inlineparser.BackslashInlineProcessor;
|
||||||
import io.noties.markwon.inlineparser.BangInlineProcessor;
|
import io.noties.markwon.inlineparser.BangInlineProcessor;
|
||||||
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
|
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
|
||||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||||
@ -70,11 +67,10 @@ import ml.docilealligator.infinityforreddit.customviews.CommentIndentationView;
|
|||||||
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
|
import ml.docilealligator.infinityforreddit.customviews.SpoilerOnClickTextView;
|
||||||
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
|
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
|
||||||
import ml.docilealligator.infinityforreddit.markdown.SpoilerParserPlugin;
|
import ml.docilealligator.infinityforreddit.markdown.SpoilerParserPlugin;
|
||||||
import ml.docilealligator.infinityforreddit.markdown.SpoilerSpan;
|
import ml.docilealligator.infinityforreddit.markdown.SuperscriptInlineProcessor;
|
||||||
import ml.docilealligator.infinityforreddit.post.Post;
|
import ml.docilealligator.infinityforreddit.post.Post;
|
||||||
import ml.docilealligator.infinityforreddit.utils.APIUtils;
|
import ml.docilealligator.infinityforreddit.utils.APIUtils;
|
||||||
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
|
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
|
||||||
import ml.docilealligator.infinityforreddit.markdown.SuperscriptInlineProcessor;
|
|
||||||
import ml.docilealligator.infinityforreddit.utils.Utils;
|
import ml.docilealligator.infinityforreddit.utils.Utils;
|
||||||
import retrofit2.Retrofit;
|
import retrofit2.Retrofit;
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ public class CopyTextBottomSheetFragment extends LandscapeExpandedRoundedBottomS
|
|||||||
|
|
||||||
if (markdownText != null) {
|
if (markdownText != null) {
|
||||||
//markdownText = markdownText.replaceAll("<sup>", "^").replaceAll("</sup>", "");
|
//markdownText = markdownText.replaceAll("<sup>", "^").replaceAll("</sup>", "");
|
||||||
markdownText = markdownText.replaceAll(">!", ">!");
|
|
||||||
copyMarkdownTextView.setOnClickListener(view -> {
|
copyMarkdownTextView.setOnClickListener(view -> {
|
||||||
showCopyDialog(markdownText);
|
showCopyDialog(markdownText);
|
||||||
dismiss();
|
dismiss();
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package ml.docilealligator.infinityforreddit.markdown;
|
||||||
|
|
||||||
|
import org.commonmark.internal.util.Parsing;
|
||||||
|
import org.commonmark.node.Block;
|
||||||
|
import org.commonmark.node.BlockQuote;
|
||||||
|
import org.commonmark.parser.block.AbstractBlockParser;
|
||||||
|
import org.commonmark.parser.block.AbstractBlockParserFactory;
|
||||||
|
import org.commonmark.parser.block.BlockContinue;
|
||||||
|
import org.commonmark.parser.block.BlockStart;
|
||||||
|
import org.commonmark.parser.block.MatchedBlockParser;
|
||||||
|
import org.commonmark.parser.block.ParserState;
|
||||||
|
|
||||||
|
// Parse and consume a block quote except when it's a spoiler opening
|
||||||
|
public class BlockQuoteWithExceptionParser extends AbstractBlockParser {
|
||||||
|
private final BlockQuote block = new BlockQuote();
|
||||||
|
|
||||||
|
private static boolean isMarker(ParserState state, int index) {
|
||||||
|
CharSequence line = state.getLine();
|
||||||
|
return state.getIndent() < Parsing.CODE_BLOCK_INDENT && index < line.length() && line.charAt(index) == '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMarkerSpoiler(ParserState state, int index) {
|
||||||
|
CharSequence line = state.getLine();
|
||||||
|
int length = line.length();
|
||||||
|
try {
|
||||||
|
return state.getIndent() < Parsing.CODE_BLOCK_INDENT && index < length && line.charAt(index) == '>' && (index + 1) < length && line.charAt(index + 1) == '!';
|
||||||
|
} catch (IndexOutOfBoundsException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isContainer() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canContain(Block block) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockQuote getBlock() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockContinue tryContinue(ParserState state) {
|
||||||
|
int nextNonSpace = state.getNextNonSpaceIndex();
|
||||||
|
if (isMarker(state, nextNonSpace)) {
|
||||||
|
int newColumn = state.getColumn() + state.getIndent() + 1;
|
||||||
|
// optional following space or tab
|
||||||
|
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
|
||||||
|
newColumn++;
|
||||||
|
}
|
||||||
|
return BlockContinue.atColumn(newColumn);
|
||||||
|
} else {
|
||||||
|
return BlockContinue.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Factory extends AbstractBlockParserFactory {
|
||||||
|
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
|
||||||
|
int nextNonSpace = state.getNextNonSpaceIndex();
|
||||||
|
// Potential for a spoiler opening
|
||||||
|
// We don't check for spoiler closing, neither does Reddit
|
||||||
|
if (isMarkerSpoiler(state, nextNonSpace)) {
|
||||||
|
// It might be a spoiler, don't consume
|
||||||
|
return BlockStart.none();
|
||||||
|
}
|
||||||
|
// Not a spoiler then
|
||||||
|
else if (isMarker(state, nextNonSpace)) {
|
||||||
|
int newColumn = state.getColumn() + state.getIndent() + 1;
|
||||||
|
// optional following space or tab
|
||||||
|
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
|
||||||
|
newColumn++;
|
||||||
|
}
|
||||||
|
return BlockStart.of(new BlockQuoteWithExceptionParser()).atColumn(newColumn);
|
||||||
|
} else {
|
||||||
|
return BlockStart.none();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,11 +7,20 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import org.commonmark.node.Block;
|
||||||
import java.util.regex.Pattern;
|
import org.commonmark.node.BlockQuote;
|
||||||
|
import org.commonmark.node.HtmlBlock;
|
||||||
|
import org.commonmark.node.HtmlInline;
|
||||||
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||||
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
|
import io.noties.markwon.core.CorePlugin;
|
||||||
|
import io.noties.markwon.core.spans.CodeBlockSpan;
|
||||||
|
import io.noties.markwon.core.spans.CodeSpan;
|
||||||
|
|
||||||
public class SpoilerParserPlugin extends AbstractMarkwonPlugin {
|
public class SpoilerParserPlugin extends AbstractMarkwonPlugin {
|
||||||
private final int textColor;
|
private final int textColor;
|
||||||
@ -26,40 +35,158 @@ public class SpoilerParserPlugin extends AbstractMarkwonPlugin {
|
|||||||
return new SpoilerParserPlugin(textColor, backgroundColor);
|
return new SpoilerParserPlugin(textColor, backgroundColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
builder.customBlockParserFactory(new BlockQuoteWithExceptionParser.Factory());
|
||||||
|
|
||||||
|
Set<Class<? extends Block>> blocks = CorePlugin.enabledBlockTypes();
|
||||||
|
blocks.remove(HtmlBlock.class);
|
||||||
|
blocks.remove(HtmlInline.class);
|
||||||
|
blocks.remove(BlockQuote.class);
|
||||||
|
|
||||||
|
builder.enabledBlockTypes(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterSetText(@NonNull TextView textView) {
|
public void afterSetText(@NonNull TextView textView) {
|
||||||
textView.setHighlightColor(Color.TRANSPARENT);
|
textView.setHighlightColor(Color.TRANSPARENT);
|
||||||
SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText());
|
SpannableStringBuilder markdownStringBuilder = new SpannableStringBuilder(textView.getText());
|
||||||
Pattern spoilerPattern = Pattern.compile(">!(\\n?(?:.+?(?:\\n?.+?)?)\\n?)!<");
|
|
||||||
Matcher matcher = spoilerPattern.matcher(markdownStringBuilder);
|
LinkedHashMap<Integer, Integer> spoilers = parse(markdownStringBuilder);
|
||||||
int start = 0;
|
int offset = 2;
|
||||||
boolean find = false;
|
|
||||||
while (matcher.find(start)) {
|
for (var entry : spoilers.entrySet()) {
|
||||||
if (markdownStringBuilder.length() < 4
|
int spoilerStart = entry.getKey() - offset;
|
||||||
|| matcher.start() < 0
|
int spoilerEnd = entry.getValue() - offset;
|
||||||
|| matcher.end() > markdownStringBuilder.length()) {
|
|
||||||
break;
|
CodeSpan[] codeSpans = markdownStringBuilder.getSpans(spoilerStart, spoilerEnd, CodeSpan.class);
|
||||||
|
CodeBlockSpan[] codeBlockSpans = markdownStringBuilder.getSpans(spoilerStart, spoilerEnd, CodeBlockSpan.class);
|
||||||
|
|
||||||
|
if (codeSpans.length == 0 && codeBlockSpans.length == 0) {
|
||||||
|
markdownStringBuilder.delete(spoilerStart, spoilerStart + 2);
|
||||||
|
markdownStringBuilder.delete(spoilerEnd, spoilerEnd + 2);
|
||||||
|
SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor);
|
||||||
|
markdownStringBuilder.setSpan(spoilerSpan, spoilerStart, spoilerEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
offset += 4;
|
||||||
|
}
|
||||||
|
s
|
||||||
|
for (CodeSpan codeSpan : codeSpans) {
|
||||||
|
int spanBeginning = markdownStringBuilder.getSpanStart(codeSpan);
|
||||||
|
int spanEnd = markdownStringBuilder.getSpanEnd(codeSpan);
|
||||||
|
if (spoilerStart < spanBeginning && spanEnd < spoilerEnd) {
|
||||||
|
markdownStringBuilder.delete(spoilerStart, spoilerStart + 2);
|
||||||
|
markdownStringBuilder.delete(spoilerEnd, spoilerEnd + 2);
|
||||||
|
SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor);
|
||||||
|
markdownStringBuilder.setSpan(spoilerSpan, spoilerStart, spoilerEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
offset += 4;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CodeBlockSpan codeBlockSpan : codeBlockSpans) {
|
||||||
|
int spanBeginning = markdownStringBuilder.getSpanStart(codeBlockSpan);
|
||||||
|
int spanEnd = markdownStringBuilder.getSpanEnd(codeBlockSpan);
|
||||||
|
if (spoilerStart < spanBeginning && spanEnd < spoilerEnd) {
|
||||||
|
markdownStringBuilder.delete(spoilerStart, spoilerStart + 2);
|
||||||
|
markdownStringBuilder.delete(spoilerEnd, spoilerEnd + 2);
|
||||||
|
SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor);
|
||||||
|
markdownStringBuilder.setSpan(spoilerSpan, spoilerStart, spoilerEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
offset += 4;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
find = true;
|
|
||||||
markdownStringBuilder.delete(matcher.end() - 2, matcher.end());
|
|
||||||
markdownStringBuilder.delete(matcher.start(), matcher.start() + 2);
|
|
||||||
SpoilerSpan spoilerSpan = new SpoilerSpan(textColor, backgroundColor);
|
|
||||||
markdownStringBuilder.setSpan(spoilerSpan, matcher.start(), matcher.end() - 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
start = matcher.end() - 4;
|
|
||||||
}
|
}
|
||||||
/*Pattern escapedSpoilerOpenerPattern = Pattern.compile(">!");
|
|
||||||
Matcher escapedSpoilerOpenerMatcher = escapedSpoilerOpenerPattern.matcher(markdownStringBuilder);
|
textView.setText(markdownStringBuilder);
|
||||||
ArrayList<Integer> matched = new ArrayList<>();
|
}
|
||||||
while (escapedSpoilerOpenerMatcher.find()) {
|
|
||||||
matched.add(escapedSpoilerOpenerMatcher.start());
|
// Very naive implementation, needs to be improved for efficiency and edge cases
|
||||||
find = true;
|
// 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
|
||||||
|
// Try not to set a spoiler span if it's inside a CodeSpan
|
||||||
|
private LinkedHashMap<Integer, Integer> parse(SpannableStringBuilder markdown) {
|
||||||
|
final int MAX_NEW_LINE = 1;
|
||||||
|
var openSpoilerStack = new Stack<Integer>();
|
||||||
|
var closedSpoilerMap = new LinkedHashMap<Integer, Integer>();
|
||||||
|
int variable_max_depth = calculateBalance(0, markdown) + 1;
|
||||||
|
int new_lines = 0;
|
||||||
|
int depth = 0;
|
||||||
|
for (int i = 0; i < markdown.length(); i++) {
|
||||||
|
if (markdown.charAt(i) == '\u2000' || markdown.charAt(i) == '\t') {
|
||||||
|
continue;
|
||||||
|
} else if (markdown.charAt(i) == '>' && (i + 1) < markdown.length() && markdown.charAt(i + 1) == '!') {
|
||||||
|
openSpoilerStack.push(i + 1);
|
||||||
|
depth++;
|
||||||
|
} else if (openSpoilerStack.size() > 0
|
||||||
|
&& markdown.charAt(i) == '!' && (i + 1) < markdown.length()
|
||||||
|
&& markdown.charAt(i + 1) == '<') {
|
||||||
|
var pos = i + 1;
|
||||||
|
for (int j = 0; j < depth; j++) {
|
||||||
|
if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek();
|
||||||
|
if (pos + 1 <= i) {
|
||||||
|
if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.peek();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!openSpoilerStack.isEmpty()) pos = openSpoilerStack.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (depth <= variable_max_depth && pos + 1 <= i) //Spoiler content cannot be zero or less length
|
||||||
|
{
|
||||||
|
openSpoilerStack.clear();
|
||||||
|
closedSpoilerMap.put(pos + 1, i);
|
||||||
|
}
|
||||||
|
depth--;
|
||||||
|
} else if (markdown.charAt(i) == '\n') {
|
||||||
|
new_lines++;
|
||||||
|
if (openSpoilerStack.size() >= 1 && new_lines > MAX_NEW_LINE) {
|
||||||
|
openSpoilerStack.clear();
|
||||||
|
new_lines = 0;
|
||||||
|
depth = 0;
|
||||||
|
variable_max_depth = calculateBalance(i, markdown) + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_lines = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openSpoilerStack.size() >= 32) // No
|
||||||
|
{
|
||||||
|
openSpoilerStack.clear();
|
||||||
|
closedSpoilerMap.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i = matched.size() - 1; i >= 0; i--) {
|
return closedSpoilerMap;
|
||||||
markdownStringBuilder.replace(matched.get(i), matched.get(i) + 4, ">");
|
}
|
||||||
}*/
|
|
||||||
if (find) {
|
private int calculateBalance(int index, SpannableStringBuilder line) {
|
||||||
textView.setText(markdownStringBuilder);
|
final int MAX_NEW_LINE = 1;
|
||||||
|
int new_lines = 0;
|
||||||
|
int opening = 0;
|
||||||
|
int closing = 0;
|
||||||
|
for (int i = index; i < line.length(); i++) {
|
||||||
|
if (line.charAt(i) == '\u0020' || line.charAt(i) == '\t') {
|
||||||
|
continue;
|
||||||
|
} else if (line.charAt(i) == '>'
|
||||||
|
&& (i + 1) < line.length()
|
||||||
|
&& line.charAt(i + 1) == '!') {
|
||||||
|
opening++;
|
||||||
|
} else if (line.charAt(i) == '!' && (i + 1) < line.length()
|
||||||
|
&& line.charAt(i + 1) == '<') {
|
||||||
|
closing++;
|
||||||
|
} else if (line.charAt(i) == '\n') {
|
||||||
|
new_lines++;
|
||||||
|
if (new_lines > MAX_NEW_LINE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
new_lines = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return Math.abs(opening - closing);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ public class SpoilerSpan extends ClickableSpan {
|
|||||||
@Override
|
@Override
|
||||||
public void updateDrawState(@NonNull TextPaint ds) {
|
public void updateDrawState(@NonNull TextPaint ds) {
|
||||||
if (isShowing) {
|
if (isShowing) {
|
||||||
|
ds.bgColor = backgroundColor & 0x0D000000; //Slightly darker background color for revealed spoiler
|
||||||
super.updateDrawState(ds);
|
super.updateDrawState(ds);
|
||||||
} else {
|
} else {
|
||||||
ds.bgColor = backgroundColor;
|
ds.bgColor = backgroundColor;
|
||||||
|
@ -65,7 +65,6 @@ public class Utils {
|
|||||||
.replaceAll("((?<=[\\s])|^)/[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com$0)")
|
.replaceAll("((?<=[\\s])|^)/[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com$0)")
|
||||||
.replaceAll("((?<=[\\s])|^)[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com/$0)")
|
.replaceAll("((?<=[\\s])|^)[rRuU]/[\\w-]+/{0,1}", "[$0](https://www.reddit.com/$0)")
|
||||||
.replaceAll("\\^{2,}", "^")
|
.replaceAll("\\^{2,}", "^")
|
||||||
.replaceAll(">!(\\n?(?:.+?(?:\\n?.+?)?)\\n?)!<", ">!$1!<") // html entity remains escaped inside an inline block
|
|
||||||
.replaceAll("(^|^ *|\\n *)#(?!($|\\s|#))", "$0 ")
|
.replaceAll("(^|^ *|\\n *)#(?!($|\\s|#))", "$0 ")
|
||||||
.replaceAll("(^|^ *|\\n *)##(?!($|\\s|#))", "$0 ")
|
.replaceAll("(^|^ *|\\n *)##(?!($|\\s|#))", "$0 ")
|
||||||
.replaceAll("(^|^ *|\\n *)###(?!($|\\s|#))", "$0 ")
|
.replaceAll("(^|^ *|\\n *)###(?!($|\\s|#))", "$0 ")
|
||||||
|
Loading…
Reference in New Issue
Block a user