Merge bef7fd235fb214424a3e156a9eaa76830a82ba9e into 5ef985670a8614b9c6e2342b7c0146c7cd936a12

This commit is contained in:
Cyrus Bakhtiari-Haftlang 2018-07-12 12:20:21 +00:00 committed by GitHub
commit 3eef075db9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 289 additions and 342 deletions

View File

@ -0,0 +1,42 @@
package ru.noties.markwon;
import android.text.SpannableStringBuilder;
/**
* Copied as is from @see <a href = "https://github.com/Uncodin/bypass/blob/master/platform/android/
* library/src/in/uncod/android/bypass/ReverseSpannableStringBuilder.java">Uncodin/bypass</a>
*/
public class ReverseSpannableStringBuilder extends SpannableStringBuilder {
public ReverseSpannableStringBuilder() {
super();
}
public ReverseSpannableStringBuilder(CharSequence text, int start, int end) {
super(text, start, end);
}
@Override
public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
T[] ret = super.getSpans(queryStart, queryEnd, kind);
reverse(ret);
return ret;
}
private static void reverse(Object[] arr) {
if (arr == null) {
return;
}
int i = 0;
int j = arr.length - 1;
Object tmp;
while (j > i) {
tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
j--;
i++;
}
}
}

View File

@ -0,0 +1,127 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.text.style.StrikethroughSpan;
import ru.noties.markwon.renderer.ImageSizeResolver;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.AsyncDrawableSpan;
import ru.noties.markwon.spans.BlockQuoteSpan;
import ru.noties.markwon.spans.BulletListItemSpan;
import ru.noties.markwon.spans.CodeSpan;
import ru.noties.markwon.spans.EmphasisSpan;
import ru.noties.markwon.spans.HeadingSpan;
import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.spans.SpanFactory;
import ru.noties.markwon.spans.SpannableTheme;
import ru.noties.markwon.spans.StrongEmphasisSpan;
import ru.noties.markwon.spans.TaskListSpan;
import ru.noties.markwon.spans.ThematicBreakSpan;
public class SpanFactoryDef implements SpanFactory {
@NonNull
private final SpannableTheme theme;
@NonNull
private final LinkSpan.Resolver linkResolver;
@NonNull
private final AsyncDrawable.Loader drawableLoader;
@NonNull
private final ImageSizeResolver imageSizeResolver;
public SpanFactoryDef(@NonNull SpannableTheme theme,
@NonNull LinkSpan.Resolver linkResolver,
@NonNull AsyncDrawable.Loader drawableLoader,
@NonNull ImageSizeResolver imageSizeResolver) {
this.theme = theme;
this.linkResolver = linkResolver;
this.drawableLoader = drawableLoader;
this.imageSizeResolver = imageSizeResolver;
}
@NonNull
@Override
public Object createBlockQuote() {
return new BlockQuoteSpan(theme);
}
@NonNull
@Override
public Object createBulletListItem(int level) {
return new BulletListItemSpan(theme, level);
}
@NonNull
@Override
public Object createCode(boolean multiline) {
return new CodeSpan(theme, multiline);
}
@NonNull
@Override
public Object createEmphasis() {
return new EmphasisSpan();
}
@NonNull
@Override
public Object createHeading(int level) {
return new HeadingSpan(theme, level);
}
@NonNull
@Override
public Object createImage(@NonNull String destination, boolean link) {
return new AsyncDrawableSpan(
theme,
new AsyncDrawable(
destination,
drawableLoader,
imageSizeResolver,
null
),
AsyncDrawableSpan.ALIGN_BOTTOM,
link
);
}
@NonNull
@Override
public Object createLink(@NonNull String destination) {
return new LinkSpan(theme, destination, linkResolver);
}
@NonNull
@Override
public Object createOrderedListItem(int order) {
// todo| in order to provide real RTL experience there must be a way to provide this string
return new OrderedListItemSpan(theme, String.valueOf(order) + "." + '\u00a0');
}
@NonNull
@Override
public Object createStrikethrough() {
return new StrikethroughSpan();
}
@NonNull
@Override
public Object createStrongEmphasis() {
return new StrongEmphasisSpan();
}
@NonNull
@Override
public Object createTaskList(int indent, boolean done) {
return new TaskListSpan(theme, indent, done);
}
@NonNull
@Override
public Object createThematicBreak() {
return new ThematicBreakSpan(theme);
}
}

View File

@ -1,245 +0,0 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
/**
* This class is used to _revert_ order of applied spans. Original SpannableStringBuilder
* is using an array to store all the information about spans. So, a span that is added first
* will be drawn first, which leads to subtle bugs (spans receive wrong `x` values when
* requested to draw itself)
*
* @since 1.0.1
*/
@SuppressWarnings({"WeakerAccess", "unused"})
public class SpannableBuilder {
// do not implement CharSequence (or any of Spanned interfaces)
// we will be using SpannableStringBuilder anyway as a backing store
// as it has tight connection with system (implements some hidden methods, etc)
private final SpannableStringBuilder builder;
// actually we might be just using ArrayList
private final Deque<Span> spans = new ArrayDeque<>(8);
public SpannableBuilder() {
this("");
}
public SpannableBuilder(@NonNull CharSequence cs) {
this.builder = new SpannableStringBuilderImpl(cs.toString());
copySpans(0, cs);
}
/**
* Additional method that takes a String, which is proven to NOT contain any spans
*
* @param text String to append
* @return this instance
*/
@NonNull
public SpannableBuilder append(@NonNull String text) {
builder.append(text);
return this;
}
@NonNull
public SpannableBuilder append(char c) {
builder.append(c);
return this;
}
@NonNull
public SpannableBuilder append(@NonNull CharSequence cs) {
copySpans(length(), cs);
builder.append(cs.toString());
return this;
}
@NonNull
public SpannableBuilder append(@NonNull CharSequence cs, @NonNull Object span) {
final int length = length();
append(cs);
setSpan(span, length);
return this;
}
@NonNull
public SpannableBuilder append(@NonNull CharSequence cs, @NonNull Object span, int flags) {
final int length = length();
append(cs);
setSpan(span, length, length(), flags);
return this;
}
@NonNull
public SpannableBuilder setSpan(@NonNull Object span, int start) {
return setSpan(span, start, length());
}
@NonNull
public SpannableBuilder setSpan(@NonNull Object span, int start, int end) {
return setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@NonNull
public SpannableBuilder setSpan(@NonNull Object span, int start, int end, int flags) {
spans.push(new Span(span, start, end, flags));
return this;
}
public int length() {
return builder.length();
}
public char charAt(int index) {
return builder.charAt(index);
}
public char lastChar() {
return builder.charAt(length() - 1);
}
@NonNull
public CharSequence removeFromEnd(int start) {
// this method is not intended to be used by clients
// it's a workaround to support tables
final int end = length();
// as we do not expose builder and do no apply spans to it, we are safe to NOT to convert to String
final SpannableStringBuilderImpl impl = new SpannableStringBuilderImpl(builder.subSequence(start, end));
final Iterator<Span> iterator = spans.iterator();
Span span;
while (iterator.hasNext() && ((span = iterator.next())) != null) {
if (span.start >= start && span.end <= end) {
impl.setSpan(span.what, span.start - start, span.end - start, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
iterator.remove();
}
}
builder.replace(start, end, "");
return impl;
}
@Override
@NonNull
public String toString() {
return builder.toString();
}
@NonNull
public CharSequence text() {
// okay, in order to not allow external modification and keep our spans order
// we should not return our builder
//
// plus, if this method was called -> all spans would be applied, which potentially
// breaks the order that we intend to use
// so, we will defensively copy builder
// as we do not expose builder and do no apply spans to it, we are safe to NOT to convert to String
final SpannableStringBuilderImpl impl = new SpannableStringBuilderImpl(builder);
for (Span span : spans) {
impl.setSpan(span.what, span.start, span.end, span.flags);
}
// now, let's remove trailing newLines (so small amounts of text are displayed correctly)
// @since 1.0.2
final int length = impl.length();
if (length > 0) {
int amount = 0;
for (int i = length - 1; i >=0 ; i--) {
if (Character.isWhitespace(impl.charAt(i))) {
amount += 1;
} else {
break;
}
}
if (amount > 0) {
impl.replace(length - amount, length, "");
}
}
return impl;
}
private void copySpans(final int index, @Nullable CharSequence cs) {
// we must identify already reversed Spanned...
// and (!) iterate backwards when adding (to preserve order)
if (cs instanceof Spanned) {
final Spanned spanned = (Spanned) cs;
final boolean reverse = spanned instanceof SpannedReversed;
final Object[] spans = spanned.getSpans(0, spanned.length(), Object.class);
iterate(reverse, spans, new Action() {
@Override
public void apply(Object o) {
setSpan(
o,
index + spanned.getSpanStart(o),
index + spanned.getSpanEnd(o),
spanned.getSpanFlags(o)
);
}
});
}
}
static class Span {
final Object what;
int start;
int end;
final int flags;
Span(@NonNull Object what, int start, int end, int flags) {
this.what = what;
this.start = start;
this.end = end;
this.flags = flags;
}
}
private interface Action {
void apply(Object o);
}
private static void iterate(boolean reverse, @Nullable Object[] array, @NonNull Action action) {
final int length = array != null
? array.length
: 0;
if (length > 0) {
if (reverse) {
for (int i = length - 1; i >= 0; i--) {
action.apply(array[i]);
}
} else {
for (int i = 0; i < length; i++) {
action.apply(array[i]);
}
}
}
}
}

View File

@ -8,6 +8,7 @@ import ru.noties.markwon.renderer.ImageSizeResolverDef;
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.SpanFactory;
import ru.noties.markwon.spans.SpannableTheme;
@SuppressWarnings("WeakerAccess")
@ -31,6 +32,7 @@ public class SpannableConfiguration {
private final UrlProcessor urlProcessor;
private final SpannableHtmlParser htmlParser;
private final ImageSizeResolver imageSizeResolver;
private final SpanFactory spanFactory;
private SpannableConfiguration(@NonNull Builder builder) {
this.theme = builder.theme;
@ -40,6 +42,7 @@ public class SpannableConfiguration {
this.urlProcessor = builder.urlProcessor;
this.htmlParser = builder.htmlParser;
this.imageSizeResolver = builder.imageSizeResolver;
this.spanFactory = builder.spanFactory;
}
@NonNull
@ -77,6 +80,11 @@ public class SpannableConfiguration {
return imageSizeResolver;
}
@NonNull
public SpanFactory spanFactory() {
return spanFactory;
}
@SuppressWarnings("unused")
public static class Builder {
@ -88,6 +96,7 @@ public class SpannableConfiguration {
private UrlProcessor urlProcessor;
private SpannableHtmlParser htmlParser;
private ImageSizeResolver imageSizeResolver;
private SpanFactory spanFactory;
Builder(@NonNull Context context) {
this.context = context;
@ -138,6 +147,12 @@ public class SpannableConfiguration {
return this;
}
@NonNull
public Builder spanFactory(@NonNull SpanFactory spanFactory) {
this.spanFactory = spanFactory;
return this;
}
@NonNull
public SpannableConfiguration build() {
@ -165,6 +180,10 @@ public class SpannableConfiguration {
imageSizeResolver = new ImageSizeResolverDef();
}
if (spanFactory == null) {
spanFactory = new SpanFactoryDef(theme, linkResolver, asyncDrawableLoader, imageSizeResolver);
}
if (htmlParser == null) {
htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor, linkResolver, imageSizeResolver);
}

View File

@ -1,13 +0,0 @@
package ru.noties.markwon;
import android.text.SpannableStringBuilder;
/**
* @since 1.0.1
*/
class SpannableStringBuilderImpl extends SpannableStringBuilder implements SpannedReversed {
SpannableStringBuilderImpl(CharSequence text) {
super(text);
}
}

View File

@ -1,9 +0,0 @@
package ru.noties.markwon;
import android.text.Spanned;
/**
* @since 1.0.1
*/
interface SpannedReversed extends Spanned {
}

View File

@ -2,9 +2,9 @@ package ru.noties.markwon.renderer;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.StrikethroughSpan;
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
import org.commonmark.ext.gfm.tables.TableBody;
@ -40,22 +40,11 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.ReverseSpannableStringBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.renderer.html.SpannableHtmlParser;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.AsyncDrawableSpan;
import ru.noties.markwon.spans.BlockQuoteSpan;
import ru.noties.markwon.spans.BulletListItemSpan;
import ru.noties.markwon.spans.CodeSpan;
import ru.noties.markwon.spans.EmphasisSpan;
import ru.noties.markwon.spans.HeadingSpan;
import ru.noties.markwon.spans.LinkSpan;
import ru.noties.markwon.spans.OrderedListItemSpan;
import ru.noties.markwon.spans.StrongEmphasisSpan;
import ru.noties.markwon.spans.SpanFactory;
import ru.noties.markwon.spans.TableRowSpan;
import ru.noties.markwon.spans.TaskListSpan;
import ru.noties.markwon.spans.ThematicBreakSpan;
import ru.noties.markwon.tasklist.TaskListBlock;
import ru.noties.markwon.tasklist.TaskListItem;
@ -63,7 +52,8 @@ import ru.noties.markwon.tasklist.TaskListItem;
public class SpannableMarkdownVisitor extends AbstractVisitor {
private final SpannableConfiguration configuration;
private final SpannableBuilder builder;
private final SpanFactory spanFactory;
private final SpannableStringBuilder builder;
private final Deque<HtmlInlineItem> htmlInlineItems;
private int blockQuoteIndent;
@ -75,9 +65,10 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
public SpannableMarkdownVisitor(
@NonNull SpannableConfiguration configuration,
@NonNull SpannableBuilder builder
@NonNull SpannableStringBuilder builder
) {
this.configuration = configuration;
this.spanFactory = configuration.spanFactory();
this.builder = builder;
this.htmlInlineItems = new ArrayDeque<>(2);
}
@ -91,14 +82,14 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
public void visit(StrongEmphasis strongEmphasis) {
final int length = builder.length();
visitChildren(strongEmphasis);
setSpan(length, new StrongEmphasisSpan());
setSpan(length, spanFactory.createStrongEmphasis());
}
@Override
public void visit(Emphasis emphasis) {
final int length = builder.length();
visitChildren(emphasis);
setSpan(length, new EmphasisSpan());
setSpan(length, spanFactory.createEmphasis());
}
@Override
@ -115,7 +106,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(blockQuote);
setSpan(length, new BlockQuoteSpan(configuration.theme()));
setSpan(length, spanFactory.createBlockQuote());
blockQuoteIndent -= 1;
@ -136,10 +127,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
builder.append(code.getLiteral());
builder.append('\u00a0');
setSpan(length, new CodeSpan(
configuration.theme(),
false
));
setSpan(length, spanFactory.createCode(false));
}
@Override
@ -174,10 +162,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
);
builder.append('\u00a0').append('\n');
setSpan(length, new CodeSpan(
configuration.theme(),
true
));
setSpan(length, spanFactory.createCode(true));
newLine();
builder.append('\n');
@ -217,11 +202,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(listItem);
// todo| in order to provide real RTL experience there must be a way to provide this string
setSpan(length, new OrderedListItemSpan(
configuration.theme(),
String.valueOf(start) + "." + '\u00a0'
));
setSpan(length, spanFactory.createOrderedListItem(start));
// after we have visited the children increment start number
final OrderedList orderedList = (OrderedList) parent;
@ -231,10 +212,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(listItem);
setSpan(length, new BulletListItemSpan(
configuration.theme(),
listLevel - 1
));
setSpan(length, spanFactory.createBulletListItem(listLevel - 1));
}
blockQuoteIndent -= 1;
@ -250,7 +228,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
builder.append(' '); // without space it won't render
setSpan(length, new ThematicBreakSpan(configuration.theme()));
setSpan(length, spanFactory.createThematicBreak());
newLine();
builder.append('\n');
@ -263,7 +241,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
visitChildren(heading);
setSpan(length, new HeadingSpan(configuration.theme(), heading.getLevel()));
setSpan(length, spanFactory.createHeading(heading.getLevel()));
newLine();
@ -305,7 +283,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
visitChildren(customNode);
setSpan(length, new StrikethroughSpan());
setSpan(length, spanFactory.createStrikethrough());
} else if (customNode instanceof TaskListItem) {
@ -319,11 +297,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
visitChildren(customNode);
setSpan(length, new TaskListSpan(
configuration.theme(),
blockQuoteIndent,
listItem.done()
));
setSpan(length, spanFactory.createTaskList(blockQuoteIndent, listItem.done()));
newLine();
@ -381,10 +355,9 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
if (pendingTableRow == null) {
pendingTableRow = new ArrayList<>(2);
}
pendingTableRow.add(new TableRowSpan.Cell(
tableCellAlignment(cell.getAlignment()),
builder.removeFromEnd(length)
removeFromEnd(length)
));
tableRowIsHeader = cell.isHeader();
@ -396,6 +369,22 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
return handled;
}
@NonNull
private CharSequence removeFromEnd(int start) {
// this method is not intended to be used by clients
// it's a workaround to support tables
final int end = builder.length();
// as we do not expose builder and do no apply spans to it, we are safe to NOT to convert to String
final SpannableStringBuilder impl = new ReverseSpannableStringBuilder(builder, start, end);
builder.delete(start, end);
return impl;
}
@Override
public void visit(Paragraph paragraph) {
@ -432,20 +421,7 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final boolean link = parent != null && parent instanceof Link;
final String destination = configuration.urlProcessor().process(image.getDestination());
setSpan(
length,
new AsyncDrawableSpan(
configuration.theme(),
new AsyncDrawable(
destination,
configuration.asyncDrawableLoader(),
configuration.imageSizeResolver(),
null
),
AsyncDrawableSpan.ALIGN_BOTTOM,
link
)
);
setSpan(length, spanFactory.createImage(destination, link));
// todo, maybe, if image is not inside a link, we should make it clickable, so
// user can open it in external viewer?
@ -504,16 +480,22 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
final int length = builder.length();
visitChildren(link);
final String destination = configuration.urlProcessor().process(link.getDestination());
setSpan(length, new LinkSpan(configuration.theme(), destination, configuration.linkResolver()));
setSpan(length, spanFactory.createLink(destination));
}
private void setSpan(int start, @NonNull Object span) {
builder.setSpan(span, start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
private void setSpan(int start, @NonNull Object spans) {
if (spans instanceof Object[]) {
for (final Object span : (Object[]) spans) {
builder.setSpan(span, start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} else {
builder.setSpan(spans, start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
private void newLine() {
if (builder.length() > 0
&& '\n' != builder.lastChar()) {
&& '\n' != builder.charAt(builder.length() - 1)) {
builder.append('\n');
}
}

View File

@ -1,18 +1,19 @@
package ru.noties.markwon.renderer;
import android.support.annotation.NonNull;
import android.text.SpannableStringBuilder;
import org.commonmark.node.Node;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.ReverseSpannableStringBuilder;
import ru.noties.markwon.SpannableConfiguration;
public class SpannableRenderer {
@NonNull
public CharSequence render(@NonNull SpannableConfiguration configuration, @NonNull Node node) {
final SpannableBuilder builder = new SpannableBuilder();
final SpannableStringBuilder builder = new ReverseSpannableStringBuilder();
node.accept(new SpannableMarkdownVisitor(configuration, builder));
return builder.text();
return builder;
}
}

View File

@ -0,0 +1,42 @@
package ru.noties.markwon.spans;
import android.support.annotation.NonNull;
public interface SpanFactory {
@NonNull
Object createBlockQuote();
@NonNull
Object createBulletListItem(int level);
@NonNull
Object createCode(boolean multiline);
@NonNull
Object createEmphasis();
@NonNull
Object createHeading(int level);
@NonNull
Object createImage(@NonNull String destination, boolean link);
@NonNull
Object createLink(@NonNull String destination);
@NonNull
Object createOrderedListItem(int order);
@NonNull
Object createStrongEmphasis();
@NonNull
Object createStrikethrough();
@NonNull
Object createTaskList(int indent, boolean done);
@NonNull
Object createThematicBreak();
}

View File

@ -1,25 +1,25 @@
package ru.noties.markwon.sample.extension;
import android.support.annotation.NonNull;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.widget.TextView;
import org.commonmark.node.CustomNode;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.renderer.SpannableMarkdownVisitor;
@SuppressWarnings("WeakerAccess")
public class IconVisitor extends SpannableMarkdownVisitor {
private final SpannableBuilder builder;
private final SpannableStringBuilder builder;
private final IconSpanProvider iconSpanProvider;
public IconVisitor(
@NonNull SpannableConfiguration configuration,
@NonNull SpannableBuilder builder,
@NonNull SpannableStringBuilder builder,
@NonNull IconSpanProvider iconSpanProvider
) {
super(configuration, builder);
@ -51,7 +51,7 @@ public class IconVisitor extends SpannableMarkdownVisitor {
final int length = builder.length();
builder.append(name);
builder.setSpan(iconSpanProvider.provide(name, color, size), length);
builder.setSpan(iconSpanProvider.provide(name, color, size), length, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append(' ');
return true;

View File

@ -2,6 +2,7 @@ package ru.noties.markwon.sample.extension;
import android.app.Activity;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.widget.TextView;
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
@ -11,7 +12,7 @@ import org.commonmark.parser.Parser;
import java.util.Arrays;
import ru.noties.markwon.SpannableBuilder;
import ru.noties.markwon.ReverseSpannableStringBuilder;
import ru.noties.markwon.SpannableConfiguration;
import ru.noties.markwon.tasklist.TaskListExtension;
@ -43,7 +44,7 @@ public class MainActivity extends Activity {
final Node node = parser.parse(markdown);
final SpannableBuilder builder = new SpannableBuilder();
final SpannableStringBuilder builder = new ReverseSpannableStringBuilder();
// please note that here I am passing `0` as fallback it means that if markdown references
// unknown icon, it will try to load fallback one and will fail with ResourceNotFound. It's
@ -61,6 +62,6 @@ public class MainActivity extends Activity {
node.accept(visitor);
// apply
textView.setText(builder.text());
textView.setText(builder);
}
}