Add image loading plugin based on picasso library
This commit is contained in:
parent
e35d3ad044
commit
19091b5675
@ -71,7 +71,8 @@ ext {
|
|||||||
'prism4j' : 'ru.noties:prism4j:1.1.0',
|
'prism4j' : 'ru.noties:prism4j:1.1.0',
|
||||||
'debug' : 'ru.noties:debug:3.0.0@jar',
|
'debug' : 'ru.noties:debug:3.0.0@jar',
|
||||||
'adapt' : 'ru.noties:adapt:1.1.0',
|
'adapt' : 'ru.noties:adapt:1.1.0',
|
||||||
'dagger' : "com.google.dagger:dagger:$daggerVersion"
|
'dagger' : "com.google.dagger:dagger:$daggerVersion",
|
||||||
|
'picasso' : "com.squareup.picasso:picasso:2.71828"
|
||||||
]
|
]
|
||||||
|
|
||||||
deps['annotationProcessor'] = [
|
deps['annotationProcessor'] = [
|
||||||
|
@ -14,6 +14,7 @@ import org.commonmark.node.Emphasis;
|
|||||||
import org.commonmark.node.FencedCodeBlock;
|
import org.commonmark.node.FencedCodeBlock;
|
||||||
import org.commonmark.node.HardLineBreak;
|
import org.commonmark.node.HardLineBreak;
|
||||||
import org.commonmark.node.Heading;
|
import org.commonmark.node.Heading;
|
||||||
|
import org.commonmark.node.Image;
|
||||||
import org.commonmark.node.IndentedCodeBlock;
|
import org.commonmark.node.IndentedCodeBlock;
|
||||||
import org.commonmark.node.Link;
|
import org.commonmark.node.Link;
|
||||||
import org.commonmark.node.ListBlock;
|
import org.commonmark.node.ListBlock;
|
||||||
@ -30,6 +31,8 @@ import ru.noties.markwon.AbstractMarkwonPlugin;
|
|||||||
import ru.noties.markwon.MarkwonConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.MarkwonSpansFactory;
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
import ru.noties.markwon.MarkwonVisitor;
|
import ru.noties.markwon.MarkwonVisitor;
|
||||||
|
import ru.noties.markwon.RenderProps;
|
||||||
|
import ru.noties.markwon.SpanFactory;
|
||||||
import ru.noties.markwon.core.factory.BlockQuoteSpanFactory;
|
import ru.noties.markwon.core.factory.BlockQuoteSpanFactory;
|
||||||
import ru.noties.markwon.core.factory.CodeBlockSpanFactory;
|
import ru.noties.markwon.core.factory.CodeBlockSpanFactory;
|
||||||
import ru.noties.markwon.core.factory.CodeSpanFactory;
|
import ru.noties.markwon.core.factory.CodeSpanFactory;
|
||||||
@ -40,6 +43,7 @@ import ru.noties.markwon.core.factory.ListItemSpanFactory;
|
|||||||
import ru.noties.markwon.core.factory.StrongEmphasisSpanFactory;
|
import ru.noties.markwon.core.factory.StrongEmphasisSpanFactory;
|
||||||
import ru.noties.markwon.core.factory.ThematicBreakSpanFactory;
|
import ru.noties.markwon.core.factory.ThematicBreakSpanFactory;
|
||||||
import ru.noties.markwon.core.spans.OrderedListItemSpan;
|
import ru.noties.markwon.core.spans.OrderedListItemSpan;
|
||||||
|
import ru.noties.markwon.image.ImageProps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see CoreProps
|
* @see CoreProps
|
||||||
@ -64,6 +68,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
code(builder);
|
code(builder);
|
||||||
fencedCodeBlock(builder);
|
fencedCodeBlock(builder);
|
||||||
indentedCodeBlock(builder);
|
indentedCodeBlock(builder);
|
||||||
|
image(builder);
|
||||||
bulletList(builder);
|
bulletList(builder);
|
||||||
orderedList(builder);
|
orderedList(builder);
|
||||||
listItem(builder);
|
listItem(builder);
|
||||||
@ -197,6 +202,53 @@ public class CorePlugin extends AbstractMarkwonPlugin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
// his method is moved from ImagesPlugin. Alternative implementations must set SpanFactory
|
||||||
|
// for Image node in order for this visitor to function
|
||||||
|
private static void image(MarkwonVisitor.Builder builder) {
|
||||||
|
builder.on(Image.class, new MarkwonVisitor.NodeVisitor<Image>() {
|
||||||
|
@Override
|
||||||
|
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) {
|
||||||
|
|
||||||
|
// if there is no image spanFactory, ignore
|
||||||
|
final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class);
|
||||||
|
if (spanFactory == null) {
|
||||||
|
visitor.visitChildren(image);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int length = visitor.length();
|
||||||
|
|
||||||
|
visitor.visitChildren(image);
|
||||||
|
|
||||||
|
// we must check if anything _was_ added, as we need at least one char to render
|
||||||
|
if (length == visitor.length()) {
|
||||||
|
visitor.builder().append('\uFFFC');
|
||||||
|
}
|
||||||
|
|
||||||
|
final MarkwonConfiguration configuration = visitor.configuration();
|
||||||
|
|
||||||
|
final Node parent = image.getParent();
|
||||||
|
final boolean link = parent instanceof Link;
|
||||||
|
|
||||||
|
final String destination = configuration
|
||||||
|
.urlProcessor()
|
||||||
|
.process(image.getDestination());
|
||||||
|
|
||||||
|
final RenderProps props = visitor.renderProps();
|
||||||
|
|
||||||
|
// apply image properties
|
||||||
|
// Please note that we explicitly set IMAGE_SIZE to null as we do not clear
|
||||||
|
// properties after we applied span (we could though)
|
||||||
|
ImageProps.DESTINATION.set(props, destination);
|
||||||
|
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link);
|
||||||
|
ImageProps.IMAGE_SIZE.set(props, null);
|
||||||
|
|
||||||
|
visitor.setSpans(length, spanFactory.getSpans(configuration, props));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static void visitCodeBlock(
|
static void visitCodeBlock(
|
||||||
@NonNull MarkwonVisitor visitor,
|
@NonNull MarkwonVisitor visitor,
|
||||||
|
@ -261,7 +261,8 @@ public class AsyncDrawable extends Drawable {
|
|||||||
if (hasResult()) {
|
if (hasResult()) {
|
||||||
out = result.getIntrinsicWidth();
|
out = result.getIntrinsicWidth();
|
||||||
} else {
|
} else {
|
||||||
out = 0;
|
// @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions
|
||||||
|
out = 1;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -272,7 +273,8 @@ public class AsyncDrawable extends Drawable {
|
|||||||
if (hasResult()) {
|
if (hasResult()) {
|
||||||
out = result.getIntrinsicHeight();
|
out = result.getIntrinsicHeight();
|
||||||
} else {
|
} else {
|
||||||
out = 0;
|
// @since 4.0.0-SNAPSHOT, must not be zero in order to receive canvas dimensions
|
||||||
|
out = 1;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -290,4 +292,16 @@ public class AsyncDrawable extends Drawable {
|
|||||||
? imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize)
|
? imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize)
|
||||||
: result.getBounds();
|
: result.getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AsyncDrawable{" +
|
||||||
|
"destination='" + destination + '\'' +
|
||||||
|
", imageSize=" + imageSize +
|
||||||
|
", result=" + result +
|
||||||
|
", canvasWidth=" + canvasWidth +
|
||||||
|
", textSize=" + textSize +
|
||||||
|
", waitingForDimensions=" + waitingForDimensions +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ public abstract class AsyncDrawableScheduler {
|
|||||||
// hm... we need the same thing for unschedule then... we can check if last hash is !null,
|
// hm... we need the same thing for unschedule then... we can check if last hash is !null,
|
||||||
// if it's not -> unschedule, else ignore
|
// if it's not -> unschedule, else ignore
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
final Integer lastTextHashCode =
|
final Integer lastTextHashCode =
|
||||||
(Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode);
|
(Integer) textView.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode);
|
||||||
final int textHashCode = textView.getText().hashCode();
|
final int textHashCode = textView.getText().hashCode();
|
||||||
@ -67,6 +68,7 @@ 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) {
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) {
|
if (view.getTag(R.id.markwon_drawables_scheduler_last_text_hashcode) == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
21
markwon-image-picasso/build.gradle
Normal file
21
markwon-image-picasso/build.gradle
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
|
||||||
|
compileSdkVersion config['compile-sdk']
|
||||||
|
buildToolsVersion config['build-tools']
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion config['min-sdk']
|
||||||
|
targetSdkVersion config['target-sdk']
|
||||||
|
versionCode 1
|
||||||
|
versionName version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(':markwon-core')
|
||||||
|
api deps['picasso']
|
||||||
|
}
|
||||||
|
|
||||||
|
registerArtifact(this)
|
4
markwon-image-picasso/gradle.properties
Normal file
4
markwon-image-picasso/gradle.properties
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
POM_NAME=Image
|
||||||
|
POM_ARTIFACT_ID=image-picasso
|
||||||
|
POM_DESCRIPTION=Markwon image loading module (based on Picasso library)
|
||||||
|
POM_PACKAGING=aar
|
1
markwon-image-picasso/src/main/AndroidManifest.xml
Normal file
1
markwon-image-picasso/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<manifest package="ru.noties.markwon.image.picasso" />
|
@ -0,0 +1,177 @@
|
|||||||
|
package ru.noties.markwon.image.picasso;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
import com.squareup.picasso.RequestCreator;
|
||||||
|
import com.squareup.picasso.Target;
|
||||||
|
|
||||||
|
import org.commonmark.node.Image;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
|
import ru.noties.markwon.image.AsyncDrawableScheduler;
|
||||||
|
import ru.noties.markwon.image.DrawableUtils;
|
||||||
|
import ru.noties.markwon.image.ImageSpanFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 4.0.0-SNAPSHOT
|
||||||
|
*/
|
||||||
|
public class PicassoImagesPlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
|
public interface PicassoStore {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
RequestCreator load(@NonNull AsyncDrawable drawable);
|
||||||
|
|
||||||
|
void cancel(@NonNull AsyncDrawable drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static PicassoImagesPlugin create(@NonNull Context context) {
|
||||||
|
return create(new Picasso.Builder(context).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static PicassoImagesPlugin create(@NonNull final Picasso picasso) {
|
||||||
|
return create(new PicassoStore() {
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RequestCreator load(@NonNull AsyncDrawable drawable) {
|
||||||
|
return picasso.load(drawable.getDestination())
|
||||||
|
.tag(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(@NonNull AsyncDrawable drawable) {
|
||||||
|
picasso.cancelTag(drawable);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static PicassoImagesPlugin create(@NonNull PicassoStore picassoStore) {
|
||||||
|
return new PicassoImagesPlugin(picassoStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final PicassoAsyncDrawableLoader picassoAsyncDrawableLoader;
|
||||||
|
|
||||||
|
PicassoImagesPlugin(@NonNull PicassoStore picassoStore) {
|
||||||
|
this.picassoAsyncDrawableLoader = new PicassoAsyncDrawableLoader(picassoStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||||
|
builder.asyncDrawableLoader(picassoAsyncDrawableLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||||
|
builder.setFactory(Image.class, new ImageSpanFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
|
AsyncDrawableScheduler.unschedule(textView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterSetText(@NonNull TextView textView) {
|
||||||
|
AsyncDrawableScheduler.schedule(textView);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PicassoAsyncDrawableLoader extends AsyncDrawableLoader {
|
||||||
|
|
||||||
|
private final PicassoStore picassoStore;
|
||||||
|
private final Map<AsyncDrawable, AsyncDrawableTarget> cache = new HashMap<>(2);
|
||||||
|
|
||||||
|
PicassoAsyncDrawableLoader(@NonNull PicassoStore picassoStore) {
|
||||||
|
this.picassoStore = picassoStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(@NonNull AsyncDrawable drawable) {
|
||||||
|
|
||||||
|
// we must store hard-reference to target (otherwise it will be garbage-collected
|
||||||
|
// ad picasso internally stores a target in a weak-reference)
|
||||||
|
final AsyncDrawableTarget target = new AsyncDrawableTarget(drawable);
|
||||||
|
cache.put(drawable, target);
|
||||||
|
|
||||||
|
picassoStore.load(drawable)
|
||||||
|
.into(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(@NonNull AsyncDrawable drawable) {
|
||||||
|
|
||||||
|
cache.remove(drawable);
|
||||||
|
|
||||||
|
picassoStore.cancel(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Drawable placeholder(@NonNull AsyncDrawable drawable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AsyncDrawableTarget implements Target {
|
||||||
|
|
||||||
|
private final AsyncDrawable drawable;
|
||||||
|
|
||||||
|
AsyncDrawableTarget(@NonNull AsyncDrawable drawable) {
|
||||||
|
this.drawable = drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||||
|
if (cache.remove(drawable) != null) {
|
||||||
|
if (drawable.isAttached() && bitmap != null) {
|
||||||
|
final BitmapDrawable bitmapDrawable = new BitmapDrawable(Resources.getSystem(), bitmap);
|
||||||
|
DrawableUtils.applyIntrinsicBounds(bitmapDrawable);
|
||||||
|
drawable.setResult(bitmapDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
|
||||||
|
if (cache.remove(drawable) != null) {
|
||||||
|
if (errorDrawable != null
|
||||||
|
&& drawable.isAttached()) {
|
||||||
|
DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable);
|
||||||
|
drawable.setResult(errorDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPrepareLoad(Drawable placeHolderDrawable) {
|
||||||
|
if (placeHolderDrawable != null
|
||||||
|
&& canDeliver()) {
|
||||||
|
DrawableUtils.applyIntrinsicBoundsIfEmpty(placeHolderDrawable);
|
||||||
|
drawable.setResult(placeHolderDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canDeliver() {
|
||||||
|
return drawable.isAttached() && cache.containsKey(drawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -73,13 +73,17 @@ class AsyncDrawableLoaderBuilder {
|
|||||||
|
|
||||||
isBuilt = true;
|
isBuilt = true;
|
||||||
|
|
||||||
// if we have no schemeHandlers -> we cannot show anything
|
// we must have schemeHandlers registered (we will provide
|
||||||
// OR if we have no media decoders
|
// default media decoder if it's absent)
|
||||||
if (schemeHandlers.size() == 0
|
if (schemeHandlers.size() == 0) {
|
||||||
|| (mediaDecoders.size() == 0 && defaultMediaDecoder == null)) {
|
|
||||||
return new AsyncDrawableLoaderNoOp();
|
return new AsyncDrawableLoaderNoOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @since 4.0.0-SNAPSHOT
|
||||||
|
if (defaultMediaDecoder == null) {
|
||||||
|
defaultMediaDecoder = DefaultImageMediaDecoder.create();
|
||||||
|
}
|
||||||
|
|
||||||
if (executorService == null) {
|
if (executorService == null) {
|
||||||
executorService = Executors.newCachedThreadPool();
|
executorService = Executors.newCachedThreadPool();
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,12 @@ import android.text.Spanned;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.commonmark.node.Image;
|
import org.commonmark.node.Image;
|
||||||
import org.commonmark.node.Link;
|
|
||||||
import org.commonmark.node.Node;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
import ru.noties.markwon.MarkwonConfiguration;
|
import ru.noties.markwon.MarkwonConfiguration;
|
||||||
import ru.noties.markwon.MarkwonSpansFactory;
|
import ru.noties.markwon.MarkwonSpansFactory;
|
||||||
import ru.noties.markwon.MarkwonVisitor;
|
|
||||||
import ru.noties.markwon.RenderProps;
|
|
||||||
import ru.noties.markwon.SpanFactory;
|
|
||||||
|
|
||||||
public class ImagesPlugin extends AbstractMarkwonPlugin {
|
public class ImagesPlugin extends AbstractMarkwonPlugin {
|
||||||
|
|
||||||
@ -147,51 +142,6 @@ public class ImagesPlugin extends AbstractMarkwonPlugin {
|
|||||||
builder.setFactory(Image.class, new ImageSpanFactory());
|
builder.setFactory(Image.class, new ImageSpanFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
|
||||||
builder.on(Image.class, new MarkwonVisitor.NodeVisitor<Image>() {
|
|
||||||
@Override
|
|
||||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Image image) {
|
|
||||||
|
|
||||||
// if there is no image spanFactory, ignore
|
|
||||||
final SpanFactory spanFactory = visitor.configuration().spansFactory().get(Image.class);
|
|
||||||
if (spanFactory == null) {
|
|
||||||
visitor.visitChildren(image);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int length = visitor.length();
|
|
||||||
|
|
||||||
visitor.visitChildren(image);
|
|
||||||
|
|
||||||
// we must check if anything _was_ added, as we need at least one char to render
|
|
||||||
if (length == visitor.length()) {
|
|
||||||
visitor.builder().append('\uFFFC');
|
|
||||||
}
|
|
||||||
|
|
||||||
final MarkwonConfiguration configuration = visitor.configuration();
|
|
||||||
|
|
||||||
final Node parent = image.getParent();
|
|
||||||
final boolean link = parent instanceof Link;
|
|
||||||
|
|
||||||
final String destination = configuration
|
|
||||||
.urlProcessor()
|
|
||||||
.process(image.getDestination());
|
|
||||||
|
|
||||||
final RenderProps props = visitor.renderProps();
|
|
||||||
|
|
||||||
// apply image properties
|
|
||||||
// Please note that we explicitly set IMAGE_SIZE to null as we do not clear
|
|
||||||
// properties after we applied span (we could though)
|
|
||||||
ImageProps.DESTINATION.set(props, destination);
|
|
||||||
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(props, link);
|
|
||||||
ImageProps.IMAGE_SIZE.set(props, null);
|
|
||||||
|
|
||||||
visitor.setSpans(length, spanFactory.getSpans(configuration, props));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||||
AsyncDrawableScheduler.unschedule(textView);
|
AsyncDrawableScheduler.unschedule(textView);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.noties.markwon.image.file;
|
package ru.noties.markwon.image.file;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -35,6 +36,16 @@ public class FileSchemeHandler extends SchemeHandler {
|
|||||||
return new FileSchemeHandler(assetManager);
|
return new FileSchemeHandler(assetManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #createWithAssets(AssetManager)
|
||||||
|
* @see ru.noties.markwon.urlprocessor.UrlProcessorAndroidAssets
|
||||||
|
* @since 4.0.0-SNAPSHOT
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static FileSchemeHandler createWithAssets(@NonNull Context context) {
|
||||||
|
return new FileSchemeHandler(context.getAssets());
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static FileSchemeHandler create() {
|
public static FileSchemeHandler create() {
|
||||||
return new FileSchemeHandler(null);
|
return new FileSchemeHandler(null);
|
||||||
|
@ -44,6 +44,8 @@ dependencies {
|
|||||||
implementation project(':markwon-recycler')
|
implementation project(':markwon-recycler')
|
||||||
implementation project(':markwon-recycler-table')
|
implementation project(':markwon-recycler-table')
|
||||||
|
|
||||||
|
implementation project(':markwon-image-picasso')
|
||||||
|
|
||||||
deps.with {
|
deps.with {
|
||||||
implementation it['support-recycler-view']
|
implementation it['support-recycler-view']
|
||||||
implementation it['okhttp']
|
implementation it['okhttp']
|
||||||
|
@ -2,6 +2,8 @@ package ru.noties.markwon.sample.recycler;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
@ -10,6 +12,9 @@ import android.support.v7.widget.LinearLayoutManager;
|
|||||||
import android.support.v7.widget.RecyclerView;
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
import com.squareup.picasso.RequestCreator;
|
||||||
|
|
||||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||||
import org.commonmark.node.FencedCodeBlock;
|
import org.commonmark.node.FencedCodeBlock;
|
||||||
|
|
||||||
@ -26,11 +31,8 @@ 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.DefaultImageMediaDecoder;
|
import ru.noties.markwon.image.AsyncDrawable;
|
||||||
import ru.noties.markwon.image.ImagesPlugin;
|
import ru.noties.markwon.image.picasso.PicassoImagesPlugin;
|
||||||
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;
|
||||||
@ -77,13 +79,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.create(plugin -> {
|
// .usePlugin(ImagesPlugin.create(plugin -> {
|
||||||
plugin
|
// plugin
|
||||||
.addSchemeHandler(FileSchemeHandler.createWithAssets(context.getAssets()))
|
// .addSchemeHandler(FileSchemeHandler.createWithAssets(context))
|
||||||
.addSchemeHandler(OkHttpNetworkSchemeHandler.create())
|
// .addSchemeHandler(OkHttpNetworkSchemeHandler.create())
|
||||||
.addMediaDecoder(SvgMediaDecoder.create())
|
// .addMediaDecoder(SvgMediaDecoder.create());
|
||||||
.defaultMediaDecoder(DefaultImageMediaDecoder.create());
|
// }))
|
||||||
}))
|
.usePlugin(PicassoImagesPlugin.create(context))
|
||||||
// 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())
|
||||||
|
@ -7,6 +7,7 @@ include ':app', ':sample',
|
|||||||
':markwon-ext-tasklist',
|
':markwon-ext-tasklist',
|
||||||
':markwon-html',
|
':markwon-html',
|
||||||
':markwon-image',
|
':markwon-image',
|
||||||
|
':markwon-image-picasso',
|
||||||
':markwon-recycler',
|
':markwon-recycler',
|
||||||
':markwon-recycler-table',
|
':markwon-recycler-table',
|
||||||
':markwon-syntax-highlight',
|
':markwon-syntax-highlight',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user