Update jlatex plugin to be independent of images
This commit is contained in:
parent
64af306e53
commit
e35d3ad044
@ -1,2 +1,6 @@
|
|||||||
* `Markwon.builder` won't require CorePlugin registration (it is done automatically)
|
* `Markwon.builder` won't require CorePlugin registration (it is done automatically)
|
||||||
to create a builder without CorePlugin - use `Markwon#builderNoCore`
|
to create a builder without CorePlugin - use `Markwon#builderNoCore`
|
||||||
|
* `JLatex` plugin now is not dependent on ImagesPlugin
|
||||||
|
also accepts a ExecutorService (optional, by default cachedThreadPool is used)
|
||||||
|
* AsyncDrawableScheduler now can be called by multiple plugins without penalty
|
||||||
|
internally caches latest state and skips scheduling if drawables are already processed
|
@ -5,23 +5,37 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.style.DynamicDrawableSpan;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import ru.noties.markwon.renderer.R;
|
import ru.noties.markwon.renderer.R;
|
||||||
|
|
||||||
public abstract class AsyncDrawableScheduler {
|
public abstract class AsyncDrawableScheduler {
|
||||||
|
|
||||||
public static void schedule(@NonNull final TextView textView) {
|
public static void schedule(@NonNull final TextView textView) {
|
||||||
|
|
||||||
final List<AsyncDrawable> list = extract(textView);
|
// we need a simple check if current text has already scheduled drawables
|
||||||
if (list.size() > 0) {
|
// we need this in order to allow multiple calls to schedule (different plugins
|
||||||
|
// might use AsyncDrawable), but we do not want to repeat the task
|
||||||
|
//
|
||||||
|
// hm... we need the same thing for unschedule then... we can check if last hash is !null,
|
||||||
|
// if it's not -> unschedule, else ignore
|
||||||
|
|
||||||
|
final Integer lastTextHashCode =
|
||||||
|
(Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode);
|
||||||
|
final int textHashCode = textView.getText().hashCode();
|
||||||
|
if (lastTextHashCode != null
|
||||||
|
&& lastTextHashCode == textHashCode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
textView.setTag(R.id.markwon_drawables_scheduler_last_text_hashcode, textHashCode);
|
||||||
|
|
||||||
|
|
||||||
|
final AsyncDrawableSpan[] spans = extractSpans(textView);
|
||||||
|
if (spans != null
|
||||||
|
&& spans.length > 0) {
|
||||||
|
|
||||||
if (textView.getTag(R.id.markwon_drawables_scheduler) == null) {
|
if (textView.getTag(R.id.markwon_drawables_scheduler) == null) {
|
||||||
final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
|
final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
|
||||||
@ -41,7 +55,10 @@ public abstract class AsyncDrawableScheduler {
|
|||||||
textView.setTag(R.id.markwon_drawables_scheduler, listener);
|
textView.setTag(R.id.markwon_drawables_scheduler, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (AsyncDrawable drawable : list) {
|
AsyncDrawable drawable;
|
||||||
|
|
||||||
|
for (AsyncDrawableSpan span : spans) {
|
||||||
|
drawable = span.getDrawable();
|
||||||
drawable.setCallback2(new DrawableCallbackImpl(textView, drawable.getBounds()));
|
drawable.setCallback2(new DrawableCallbackImpl(textView, drawable.getBounds()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,57 +66,39 @@ public abstract class AsyncDrawableScheduler {
|
|||||||
|
|
||||||
// must be called when text manually changed in TextView
|
// must be called when text manually changed in TextView
|
||||||
public static void unschedule(@NonNull TextView view) {
|
public static void unschedule(@NonNull TextView view) {
|
||||||
for (AsyncDrawable drawable : extract(view)) {
|
|
||||||
drawable.setCallback2(null);
|
if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
view.setTag(R.id.markwon_drawables_scheduler_last_text_hashcode, null);
|
||||||
|
|
||||||
|
|
||||||
|
final AsyncDrawableSpan[] spans = extractSpans(view);
|
||||||
|
if (spans != null
|
||||||
|
&& spans.length > 0) {
|
||||||
|
for (AsyncDrawableSpan span : spans) {
|
||||||
|
span.getDrawable().setCallback2(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<AsyncDrawable> extract(@NonNull TextView view) {
|
@Nullable
|
||||||
|
private static AsyncDrawableSpan[] extractSpans(@NonNull TextView textView) {
|
||||||
|
|
||||||
final List<AsyncDrawable> list;
|
final CharSequence cs = textView.getText();
|
||||||
|
|
||||||
final CharSequence cs = view.getText();
|
|
||||||
final int length = cs != null
|
final int length = cs != null
|
||||||
? cs.length()
|
? cs.length()
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (length == 0 || !(cs instanceof Spanned)) {
|
if (length == 0
|
||||||
//noinspection unchecked
|
|| !(cs instanceof Spanned)) {
|
||||||
list = Collections.EMPTY_LIST;
|
return null;
|
||||||
} else {
|
|
||||||
|
|
||||||
final List<AsyncDrawable> drawables = new ArrayList<>(2);
|
|
||||||
|
|
||||||
final Spanned spanned = (Spanned) cs;
|
|
||||||
final AsyncDrawableSpan[] asyncDrawableSpans = spanned.getSpans(0, length, AsyncDrawableSpan.class);
|
|
||||||
if (asyncDrawableSpans != null
|
|
||||||
&& asyncDrawableSpans.length > 0) {
|
|
||||||
for (AsyncDrawableSpan span : asyncDrawableSpans) {
|
|
||||||
drawables.add(span.getDrawable());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final DynamicDrawableSpan[] dynamicDrawableSpans = spanned.getSpans(0, length, DynamicDrawableSpan.class);
|
|
||||||
if (dynamicDrawableSpans != null
|
|
||||||
&& dynamicDrawableSpans.length > 0) {
|
|
||||||
for (DynamicDrawableSpan span : dynamicDrawableSpans) {
|
|
||||||
final Drawable d = span.getDrawable();
|
|
||||||
if (d != null
|
|
||||||
&& d instanceof AsyncDrawable) {
|
|
||||||
drawables.add((AsyncDrawable) d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drawables.size() == 0) {
|
|
||||||
//noinspection unchecked
|
|
||||||
list = Collections.EMPTY_LIST;
|
|
||||||
} else {
|
|
||||||
list = drawables;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
// we also could've tried the `nextSpanTransition`, but strangely it leads to worse performance
|
||||||
|
// then direct getSpans
|
||||||
|
|
||||||
|
return ((Spanned) cs).getSpans(0, length, AsyncDrawableSpan.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AsyncDrawableScheduler() {
|
private AsyncDrawableScheduler() {
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<item name="markwon_drawables_scheduler" type="id" />
|
<item name="markwon_drawables_scheduler" type="id" />
|
||||||
|
<item name="markwon_drawables_scheduler_last_text_hashcode" type="id" />
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -16,6 +16,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
api project(':markwon-core')
|
api project(':markwon-core')
|
||||||
|
api project(':markwon-image')
|
||||||
api deps['jlatexmath-android']
|
api deps['jlatexmath-android']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,31 @@
|
|||||||
package ru.noties.markwon.ext.latex;
|
package ru.noties.markwon.ext.latex;
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.net.Uri;
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.Px;
|
import android.support.annotation.Px;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.Image;
|
|
||||||
import org.commonmark.parser.Parser;
|
import org.commonmark.parser.Parser;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.util.HashMap;
|
||||||
import java.io.InputStream;
|
import java.util.Map;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.Scanner;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import ru.noties.jlatexmath.JLatexMathDrawable;
|
import ru.noties.jlatexmath.JLatexMathDrawable;
|
||||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.MarkwonVisitor;
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
import ru.noties.markwon.RenderProps;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
|
import ru.noties.markwon.image.AsyncDrawableScheduler;
|
||||||
|
import ru.noties.markwon.image.AsyncDrawableSpan;
|
||||||
import ru.noties.markwon.image.ImageSize;
|
import ru.noties.markwon.image.ImageSize;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,27 +72,29 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
private final int padding;
|
private final int padding;
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
private final ExecutorService executorService;
|
||||||
|
|
||||||
Config(@NonNull Builder builder) {
|
Config(@NonNull Builder builder) {
|
||||||
this.textSize = builder.textSize;
|
this.textSize = builder.textSize;
|
||||||
this.background = builder.background;
|
this.background = builder.background;
|
||||||
this.align = builder.align;
|
this.align = builder.align;
|
||||||
this.fitCanvas = builder.fitCanvas;
|
this.fitCanvas = builder.fitCanvas;
|
||||||
this.padding = builder.padding;
|
this.padding = builder.padding;
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
ExecutorService executorService = builder.executorService;
|
||||||
|
if (executorService == null) {
|
||||||
|
executorService = Executors.newCachedThreadPool();
|
||||||
|
}
|
||||||
|
this.executorService = executorService;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
private final JLatextAsyncDrawableLoader jLatextAsyncDrawableLoader;
|
||||||
public static String makeDestination(@NonNull String latex) {
|
|
||||||
return SCHEME + "://" + latex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String SCHEME = "jlatexmath";
|
|
||||||
private static final String CONTENT_TYPE = "text/jlatexmath";
|
|
||||||
|
|
||||||
private final Config config;
|
|
||||||
|
|
||||||
JLatexMathPlugin(@NonNull Config config) {
|
JLatexMathPlugin(@NonNull Config config) {
|
||||||
this.config = config;
|
this.jLatextAsyncDrawableLoader = new JLatextAsyncDrawableLoader(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -102,70 +111,36 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
final String latex = jLatexMathBlock.latex();
|
final String latex = jLatexMathBlock.latex();
|
||||||
|
|
||||||
final int length = visitor.length();
|
final int length = visitor.length();
|
||||||
|
|
||||||
visitor.builder().append(latex);
|
visitor.builder().append(latex);
|
||||||
|
|
||||||
final RenderProps renderProps = visitor.renderProps();
|
final MarkwonConfiguration configuration = visitor.configuration();
|
||||||
|
|
||||||
ImageProps.DESTINATION.set(renderProps, makeDestination(latex));
|
final AsyncDrawableSpan span = new AsyncDrawableSpan(
|
||||||
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(renderProps, false);
|
configuration.theme(),
|
||||||
ImageProps.IMAGE_SIZE.set(renderProps, new ImageSize(new ImageSize.Dimension(100, "%"), null));
|
new AsyncDrawable(
|
||||||
|
latex,
|
||||||
|
jLatextAsyncDrawableLoader,
|
||||||
|
configuration.imageSizeResolver(),
|
||||||
|
new ImageSize(
|
||||||
|
new ImageSize.Dimension(100, "%"),
|
||||||
|
null)),
|
||||||
|
AsyncDrawableSpan.ALIGN_BOTTOM,
|
||||||
|
false);
|
||||||
|
|
||||||
visitor.setSpansForNode(Image.class, length);
|
visitor.setSpans(length, span);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
builder
|
AsyncDrawableScheduler.unschedule(textView);
|
||||||
.addSchemeHandler(SCHEME, new SchemeHandler() {
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
|
|
||||||
|
|
||||||
ImageItem item = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
final byte[] bytes = raw.substring(SCHEME.length()).getBytes("UTF-8");
|
|
||||||
item = new ImageItem(
|
|
||||||
CONTENT_TYPE,
|
|
||||||
new ByteArrayInputStream(bytes));
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.addMediaDecoder(CONTENT_TYPE, new MediaDecoder() {
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Drawable decode(@NonNull InputStream inputStream) {
|
|
||||||
|
|
||||||
final Scanner scanner = new Scanner(inputStream, "UTF-8").useDelimiter("\\A");
|
|
||||||
final String latex = scanner.hasNext()
|
|
||||||
? scanner.next()
|
|
||||||
: null;
|
|
||||||
|
|
||||||
if (latex == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JLatexMathDrawable.builder(latex)
|
|
||||||
.textSize(config.textSize)
|
|
||||||
.background(config.background)
|
|
||||||
.align(config.align)
|
|
||||||
.fitCanvas(config.fitCanvas)
|
|
||||||
.padding(config.padding)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
@Override
|
||||||
public Priority priority() {
|
public void afterSetText(@NonNull TextView textView) {
|
||||||
return Priority.after(ImagesPlugin.class);
|
AsyncDrawableScheduler.schedule(textView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
@ -181,6 +156,9 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
private int padding;
|
private int padding;
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
private ExecutorService executorService;
|
||||||
|
|
||||||
Builder(float textSize) {
|
Builder(float textSize) {
|
||||||
this.textSize = textSize;
|
this.textSize = textSize;
|
||||||
}
|
}
|
||||||
@ -209,9 +187,95 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.0.0-SNAPSHOT
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Builder executorService(@NonNull ExecutorService executorService) {
|
||||||
|
this.executorService = executorService;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public Config build() {
|
public Config build() {
|
||||||
return new Config(this);
|
return new Config(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
private static class JLatextAsyncDrawableLoader extends AsyncDrawableLoader {
|
||||||
|
|
||||||
|
private final Config config;
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
private final Map<AsyncDrawable, Future<?>> cache = new HashMap<>(3);
|
||||||
|
|
||||||
|
JLatextAsyncDrawableLoader(@NonNull Config config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(@NonNull final AsyncDrawable drawable) {
|
||||||
|
|
||||||
|
// this method must be called from main-thread only (thus synchronization can be skipped)
|
||||||
|
|
||||||
|
// check for currently running tasks associated with provided drawable
|
||||||
|
final Future<?> future = cache.get(drawable);
|
||||||
|
|
||||||
|
// if it's present -> proceed with new execution
|
||||||
|
// as asyncDrawable is immutable, it won't have destination changed (so there is no need
|
||||||
|
// to cancel any started tasks)
|
||||||
|
if (future == null) {
|
||||||
|
|
||||||
|
cache.put(drawable, config.executorService.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
// create JLatexMathDrawable
|
||||||
|
final JLatexMathDrawable jLatexMathDrawable =
|
||||||
|
JLatexMathDrawable.builder(drawable.getDestination())
|
||||||
|
.textSize(config.textSize)
|
||||||
|
.background(config.background)
|
||||||
|
.align(config.align)
|
||||||
|
.fitCanvas(config.fitCanvas)
|
||||||
|
.padding(config.padding)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// we must post to handler, but also have a way to identify the drawable
|
||||||
|
// for which we are posting (in case of cancellation)
|
||||||
|
handler.postAtTime(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// remove entry from cache (it will be present if task is not cancelled)
|
||||||
|
if (cache.remove(drawable) != null
|
||||||
|
&& drawable.isAttached()) {
|
||||||
|
drawable.setResult(jLatexMathDrawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}, drawable, SystemClock.uptimeMillis());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(@NonNull AsyncDrawable drawable) {
|
||||||
|
|
||||||
|
// this method also must be called from main thread only
|
||||||
|
|
||||||
|
final Future<?> future = cache.remove(drawable);
|
||||||
|
if (future != null) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove all callbacks (via runnable) and messages posted for this drawable
|
||||||
|
handler.removeCallbacksAndMessages(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Drawable placeholder(@NonNull AsyncDrawable drawable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ dependencies {
|
|||||||
implementation it['prism4j']
|
implementation it['prism4j']
|
||||||
implementation it['debug']
|
implementation it['debug']
|
||||||
implementation it['adapt']
|
implementation it['adapt']
|
||||||
|
implementation it['android-svg']
|
||||||
}
|
}
|
||||||
|
|
||||||
deps['annotationProcessor'].with {
|
deps['annotationProcessor'].with {
|
||||||
|
@ -19,9 +19,8 @@ import ru.noties.markwon.MarkwonConfiguration;
|
|||||||
import ru.noties.markwon.MarkwonPlugin;
|
import ru.noties.markwon.MarkwonPlugin;
|
||||||
import ru.noties.markwon.MarkwonSpansFactory;
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
import ru.noties.markwon.MarkwonVisitor;
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
import ru.noties.markwon.movement.MovementMethodPlugin;
|
|
||||||
import ru.noties.markwon.core.MarkwonTheme;
|
import ru.noties.markwon.core.MarkwonTheme;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.movement.MovementMethodPlugin;
|
||||||
|
|
||||||
public class BasicPluginsActivity extends Activity {
|
public class BasicPluginsActivity extends Activity {
|
||||||
|
|
||||||
@ -168,25 +167,25 @@ public class BasicPluginsActivity extends Activity {
|
|||||||
final String markdown = "";
|
final String markdown = "";
|
||||||
|
|
||||||
final Markwon markwon = Markwon.builder(this)
|
final Markwon markwon = Markwon.builder(this)
|
||||||
.usePlugin(ImagesPlugin.create(this))
|
// .usePlugin(ImagesPlugin.create(this))
|
||||||
.usePlugin(new AbstractMarkwonPlugin() {
|
// .usePlugin(new AbstractMarkwonPlugin() {
|
||||||
@Override
|
// @Override
|
||||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
// public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
||||||
// we can have a custom SchemeHandler
|
// // we can have a custom SchemeHandler
|
||||||
// here we will just use networkSchemeHandler to redirect call
|
// // here we will just use networkSchemeHandler to redirect call
|
||||||
builder.addSchemeHandler("myownscheme", new SchemeHandler() {
|
// builder.addSchemeHandler("myownscheme", new SchemeHandler() {
|
||||||
|
//
|
||||||
final NetworkSchemeHandler networkSchemeHandler = NetworkSchemeHandler.create();
|
// final NetworkSchemeHandler networkSchemeHandler = NetworkSchemeHandler.create();
|
||||||
|
//
|
||||||
@Nullable
|
// @Nullable
|
||||||
@Override
|
// @Override
|
||||||
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
|
// public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
|
||||||
raw = raw.replace("myownscheme", "https");
|
// raw = raw.replace("myownscheme", "https");
|
||||||
return networkSchemeHandler.handle(raw, Uri.parse(raw));
|
// return networkSchemeHandler.handle(raw, Uri.parse(raw));
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
markwon.setMarkdown(textView, markdown);
|
markwon.setMarkdown(textView, markdown);
|
||||||
|
@ -26,7 +26,7 @@ public class CustomExtensionActivity extends Activity {
|
|||||||
// `usePlugin` call
|
// `usePlugin` call
|
||||||
final Markwon markwon = Markwon.builder(this)
|
final Markwon markwon = Markwon.builder(this)
|
||||||
// try commenting out this line to see runtime dependency resolution
|
// try commenting out this line to see runtime dependency resolution
|
||||||
.usePlugin(ImagesPlugin.create(this))
|
// .usePlugin(ImagesPlugin.create(this))
|
||||||
.usePlugin(IconPlugin.create(IconSpanProvider.create(this, 0)))
|
.usePlugin(IconPlugin.create(IconSpanProvider.create(this, 0)))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ public class IconPlugin extends AbstractMarkwonPlugin {
|
|||||||
this.iconSpanProvider = iconSpanProvider;
|
this.iconSpanProvider = iconSpanProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
// @NonNull
|
||||||
@Override
|
// @Override
|
||||||
public Priority priority() {
|
// public Priority priority() {
|
||||||
// define images dependency
|
// // define images dependency
|
||||||
return Priority.after(ImagesPlugin.class);
|
// return Priority.after(ImagesPlugin.class);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureParser(@NonNull Parser.Builder builder) {
|
public void configureParser(@NonNull Parser.Builder builder) {
|
||||||
|
@ -42,7 +42,7 @@ public class LatexActivity extends Activity {
|
|||||||
+ latex + "$$\n\n something like **this**";
|
+ latex + "$$\n\n something like **this**";
|
||||||
|
|
||||||
final Markwon markwon = Markwon.builder(this)
|
final Markwon markwon = Markwon.builder(this)
|
||||||
.usePlugin(ImagesPlugin.create(this))
|
// .usePlugin(ImagesPlugin.create(this))
|
||||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize()))
|
.usePlugin(JLatexMathPlugin.create(textView.getTextSize()))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -26,7 +26,11 @@ import ru.noties.markwon.MarkwonConfiguration;
|
|||||||
import ru.noties.markwon.MarkwonVisitor;
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
import ru.noties.markwon.core.CorePlugin;
|
import ru.noties.markwon.core.CorePlugin;
|
||||||
import ru.noties.markwon.html.HtmlPlugin;
|
import ru.noties.markwon.html.HtmlPlugin;
|
||||||
import ru.noties.markwon.image.svg.SvgPlugin;
|
import ru.noties.markwon.image.DefaultImageMediaDecoder;
|
||||||
|
import ru.noties.markwon.image.ImagesPlugin;
|
||||||
|
import ru.noties.markwon.image.file.FileSchemeHandler;
|
||||||
|
import ru.noties.markwon.image.network.OkHttpNetworkSchemeHandler;
|
||||||
|
import ru.noties.markwon.image.svg.SvgMediaDecoder;
|
||||||
import ru.noties.markwon.recycler.MarkwonAdapter;
|
import ru.noties.markwon.recycler.MarkwonAdapter;
|
||||||
import ru.noties.markwon.recycler.SimpleEntry;
|
import ru.noties.markwon.recycler.SimpleEntry;
|
||||||
import ru.noties.markwon.recycler.table.TableEntry;
|
import ru.noties.markwon.recycler.table.TableEntry;
|
||||||
@ -73,8 +77,13 @@ public class RecyclerActivity extends Activity {
|
|||||||
private static Markwon markwon(@NonNull Context context) {
|
private static Markwon markwon(@NonNull Context context) {
|
||||||
return Markwon.builder(context)
|
return Markwon.builder(context)
|
||||||
.usePlugin(CorePlugin.create())
|
.usePlugin(CorePlugin.create())
|
||||||
.usePlugin(ImagesPlugin.createWithAssets(context))
|
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||||
.usePlugin(SvgPlugin.create(context.getResources()))
|
plugin
|
||||||
|
.addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets()))
|
||||||
|
.addSchemeHandler(OkHttpNetworkSchemeHandler.create())
|
||||||
|
.addMediaDecoder(SvgMediaDecoder.create())
|
||||||
|
.defaultMediaDecoder(DefaultImageMediaDecoder.create());
|
||||||
|
}))
|
||||||
// important to use TableEntryPlugin instead of TablePlugin
|
// important to use TableEntryPlugin instead of TablePlugin
|
||||||
.usePlugin(TableEntryPlugin.create(context))
|
.usePlugin(TableEntryPlugin.create(context))
|
||||||
.usePlugin(HtmlPlugin.create())
|
.usePlugin(HtmlPlugin.create())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user