diff --git a/README.md b/README.md
index db19a195..0041cbeb 100644
--- a/README.md
+++ b/README.md
@@ -84,7 +84,7 @@ and [3.x.x](https://github.com/noties/Markwon/tree/3.x.x) branches
## Screenshots
-Taken with default configuration (except for image loading):
+Taken with default configuration (except for image loading) in [sample app](./app-sample/):
diff --git a/app-sample/samples.json b/app-sample/samples.json
index 1e04d195..d24eb2a7 100644
--- a/app-sample/samples.json
+++ b/app-sample/samples.json
@@ -1,4 +1,16 @@
[
+ {
+ "javaClassName": "io.noties.markwon.app.samples.RedditSpoilerSample",
+ "id": "20200813145316",
+ "title": "Reddit spoiler",
+ "description": "An attempt to implement Reddit spoiler syntax `\u003e! !\u003c`",
+ "artifacts": [
+ "CORE"
+ ],
+ "tags": [
+ "parsing"
+ ]
+ },
{
"javaClassName": "io.noties.markwon.app.samples.image.CoilRecyclerViewSample",
"id": "20200803132053",
diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/RedditSpoilerSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/RedditSpoilerSample.java
new file mode 100644
index 00000000..e51ffabd
--- /dev/null
+++ b/app-sample/src/main/java/io/noties/markwon/app/samples/RedditSpoilerSample.java
@@ -0,0 +1,126 @@
+package io.noties.markwon.app.samples;
+
+import android.graphics.Color;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+import android.text.style.ClickableSpan;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import io.noties.markwon.AbstractMarkwonPlugin;
+import io.noties.markwon.Markwon;
+import io.noties.markwon.app.sample.Tags;
+import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
+import io.noties.markwon.sample.annotations.MarkwonArtifact;
+import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
+import io.noties.markwon.utils.ColorUtils;
+
+@MarkwonSampleInfo(
+ id = "20200813145316",
+ title = "Reddit spoiler",
+ description = "An attempt to implement Reddit spoiler syntax `>! !<`",
+ artifacts = MarkwonArtifact.CORE,
+ tags = Tags.parsing
+)
+public class RedditSpoilerSample extends MarkwonTextViewSample {
+ @Override
+ public void render() {
+ final String md = "" +
+ "# Reddit spolier\n\n" +
+ "Hello >!ugly so **ugly** !<, how are you?\n\n" +
+ ">!a blockquote?!< should not be >!present!< yeah" +
+ "";
+
+ final Markwon markwon = Markwon.builder(context)
+ .usePlugin(new RedditSpoilerPlugin())
+ .build();
+
+ markwon.setMarkdown(textView, md);
+ }
+}
+
+class RedditSpoilerPlugin extends AbstractMarkwonPlugin {
+
+ private static final Pattern RE = Pattern.compile(">!.+?!<");
+
+ @NonNull
+ @Override
+ public String processMarkdown(@NonNull String markdown) {
+ // replace all `>!` with `>!` so no blockquote would be parsed (when spoiler starts at new line)
+ return markdown.replaceAll(">!", ">!");
+ }
+
+ @Override
+ public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
+ applySpoilerSpans((Spannable) markdown);
+ }
+
+ private static void applySpoilerSpans(@NonNull Spannable spannable) {
+ final String text = spannable.toString();
+ final Matcher matcher = RE.matcher(text);
+
+ while (matcher.find()) {
+
+ final RedditSpoilerSpan spoilerSpan = new RedditSpoilerSpan();
+ final ClickableSpan clickableSpan = new ClickableSpan() {
+ @Override
+ public void onClick(@NonNull View widget) {
+ spoilerSpan.setRevealed(true);
+ widget.postInvalidateOnAnimation();
+ }
+
+ @Override
+ public void updateDrawState(@NonNull TextPaint ds) {
+ // no op
+ }
+ };
+
+ final int s = matcher.start();
+ final int e = matcher.end();
+ spannable.setSpan(spoilerSpan, s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ spannable.setSpan(clickableSpan, s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ // we also can hide original syntax
+ spannable.setSpan(new HideSpoilerSyntaxSpan(), s, s + 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ spannable.setSpan(new HideSpoilerSyntaxSpan(), e - 2, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ }
+
+ private static class RedditSpoilerSpan extends CharacterStyle {
+
+ private boolean revealed;
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ if (!revealed) {
+ // use the same text color
+ tp.bgColor = Color.BLACK;
+ tp.setColor(Color.BLACK);
+ } else {
+ // for example keep a bit of black background to remind that it is a spoiler
+ tp.bgColor = ColorUtils.applyAlpha(Color.BLACK, 25);
+ }
+ }
+
+ public void setRevealed(boolean revealed) {
+ this.revealed = revealed;
+ }
+ }
+
+ // we also could make text size smaller (but then MetricAffectingSpan should be used)
+ private static class HideSpoilerSyntaxSpan extends CharacterStyle {
+
+ @Override
+ public void updateDrawState(TextPaint tp) {
+ // set transparent color
+ tp.setColor(0);
+ }
+ }
+}
\ No newline at end of file