diff --git a/CHANGELOG.md b/CHANGELOG.md index fda1dbf3..96c678db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +# SNAPSHOT + +#### Changed +* `image-glide`: update to `4.11.0` version + # 4.5.1 #### Changed diff --git a/app-sample/samples.json b/app-sample/samples.json index 6acf2056..8b3dda40 100644 --- a/app-sample/samples.json +++ b/app-sample/samples.json @@ -1,4 +1,28 @@ [ + { + "javaClassName": "io.noties.markwon.app.samples.image.GlideGifImageSample", + "id": "20200820071942", + "title": "Glide GIF", + "description": "", + "artifacts": [ + "IMAGE_GLIDE" + ], + "tags": [ + "image" + ] + }, + { + "javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingSquareBracketsSample", + "id": "20200819071751", + "title": "Inline Parsing of square brackets", + "description": "Disable OpenBracketInlineParser in order to parse own markdown syntax based on `[` character(s). This would disable native markdown [links](#) but not images ![image-alt](#)", + "artifacts": [ + "INLINE_PARSER" + ], + "tags": [ + "parsing" + ] + }, { "javaClassName": "io.noties.markwon.app.samples.ThematicBreakBottomMarginSample", "id": "20200813154415", diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/image/GlideGifImageSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/image/GlideGifImageSample.java new file mode 100644 index 00000000..e0c7dc7b --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/image/GlideGifImageSample.java @@ -0,0 +1,84 @@ +package io.noties.markwon.app.samples.image; + +import android.graphics.drawable.Animatable; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.load.DataSource; +import com.bumptech.glide.load.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; + +import io.noties.markwon.Markwon; +import io.noties.markwon.app.sample.Tags; +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample; +import io.noties.markwon.image.AsyncDrawable; +import io.noties.markwon.image.glide.GlideImagesPlugin; +import io.noties.markwon.sample.annotations.MarkwonArtifact; +import io.noties.markwon.sample.annotations.MarkwonSampleInfo; + +@MarkwonSampleInfo( + id = "20200820071942", + title = "Glide GIF", + artifacts = MarkwonArtifact.IMAGE_GLIDE, + tags = Tags.image +) +public class GlideGifImageSample extends MarkwonTextViewSample { + @Override + public void render() { + final String md = "# Glide GIF\n" + + "![gif-image](https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif) " + + "and some other resource: ![image](https://github.com/dcurtis/markdown-mark/raw/master/png/208x128-solid.png)\n\n" + + "Hey: ![alt](https://picsum.photos/id/237/1024/800)"; + + final Markwon markwon = Markwon.builder(context) + .usePlugin(GlideImagesPlugin.create(new GifGlideStore(Glide.with(context)))) + .build(); + + markwon.setMarkdown(textView, md); + } + + private static class GifGlideStore implements GlideImagesPlugin.GlideStore { + private final RequestManager requestManager; + + GifGlideStore(RequestManager requestManager) { + this.requestManager = requestManager; + } + + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + // NB! Strange behaviour: First time a resource is requested - it fails, the next time it loads fine + final String destination = drawable.getDestination(); + return requestManager + // it is enough to call this (in order to load GIF and non-GIF) + .asDrawable() + .addListener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + // we must start GIF animation manually + if (resource instanceof Animatable) { + ((Animatable) resource).start(); + } + return false; + } + }) + .load(destination); + } + + @Override + public void cancel(@NonNull Target target) { + requestManager.clear(target); + } + } +} diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingSquareBracketsSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingSquareBracketsSample.java new file mode 100644 index 00000000..439ca64f --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/inlineparsing/InlineParsingSquareBracketsSample.java @@ -0,0 +1,114 @@ +package io.noties.markwon.app.samples.inlineparsing; + +import android.graphics.Color; +import android.text.style.ForegroundColorSpan; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.commonmark.node.CustomNode; +import org.commonmark.node.Node; + +import java.util.regex.Pattern; + +import io.noties.debug.Debug; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.MarkwonVisitor; +import io.noties.markwon.app.sample.Tags; +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample; +import io.noties.markwon.inlineparser.InlineProcessor; +import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin; +import io.noties.markwon.inlineparser.OpenBracketInlineProcessor; +import io.noties.markwon.sample.annotations.MarkwonArtifact; +import io.noties.markwon.sample.annotations.MarkwonSampleInfo; + +@MarkwonSampleInfo( + id = "20200819071751", + title = "Inline Parsing of square brackets", + description = "Disable OpenBracketInlineParser in order " + + "to parse own markdown syntax based on `[` character(s). This would disable native " + + "markdown [links](#) but not images ![image-alt](#)", + artifacts = MarkwonArtifact.INLINE_PARSER, + tags = {Tags.parsing} +) +public class InlineParsingSquareBracketsSample extends MarkwonTextViewSample { + @Override + public void render() { + final String md = "" + + "# Hello\n" + + "Hey! [[my text]] here and what to do with it?\n\n" + + "[[at the beginning]] of a line with [links](#) disabled"; + + final Markwon markwon = Markwon.builder(context) + .usePlugin(MarkwonInlineParserPlugin.create(factoryBuilder -> + factoryBuilder + .addInlineProcessor(new MyTextInlineProcessor()) + .excludeInlineProcessor(OpenBracketInlineProcessor.class))) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) { + builder + .on(MyTextNode.class, new GenericInlineNodeVisitor()) + .on(NotMyTextNode.class, new GenericInlineNodeVisitor()); + } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder + .setFactory(MyTextNode.class, (configuration, props) -> new ForegroundColorSpan(Color.RED)) + .setFactory(NotMyTextNode.class, (configuration, props) -> new ForegroundColorSpan(Color.GREEN)); + } + }) + .build(); + + markwon.setMarkdown(textView, md); + } + + private static class GenericInlineNodeVisitor implements MarkwonVisitor.NodeVisitor { + @Override + public void visit(@NonNull MarkwonVisitor visitor, @NonNull Node node) { + final int length = visitor.length(); + visitor.visitChildren(node); + visitor.setSpansForNodeOptional(node, length); + } + } + + private static class MyTextInlineProcessor extends InlineProcessor { + + private static final Pattern RE = Pattern.compile("\\[\\[(.+?)\\]\\]"); + + @Override + public char specialCharacter() { + return '['; + } + + @Nullable + @Override + protected Node parse() { + final String match = match(RE); + Debug.i(match); + if (match != null) { + // consume syntax + final String text = match.substring(2, match.length() - 2); + final Node node; + // for example some condition checking + if (text.equals("my text")) { + node = new MyTextNode(); + } else { + node = new NotMyTextNode(); + } + node.appendChild(text(text)); + return node; + } + return null; + } + } + + private static class MyTextNode extends CustomNode { + } + + private static class NotMyTextNode extends CustomNode { + } +} diff --git a/build.gradle b/build.gradle index 5fb64e81..f11f8b71 100644 --- a/build.gradle +++ b/build.gradle @@ -86,7 +86,7 @@ ext { 'adapt' : 'io.noties:adapt:2.2.0', 'dagger' : "com.google.dagger:dagger:$daggerVersion", 'picasso' : 'com.squareup.picasso:picasso:2.71828', - 'glide' : 'com.github.bumptech.glide:glide:4.9.0', + 'glide' : 'com.github.bumptech.glide:glide:4.11.0', 'coil' : "io.coil-kt:coil:$coilVersion", 'coil-base' : "io.coil-kt:coil-base:$coilVersion", 'ix-java' : 'com.github.akarnokd:ixjava:1.0.0', diff --git a/gradle.properties b/gradle.properties index b4bfafd3..94e63a4d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ android.enableJetifier=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=4.5.1 +VERSION_NAME=4.5.2-SNAPSHOT GROUP=io.noties.markwon POM_DESCRIPTION=Markwon markdown for Android