diff --git a/README.md b/README.md index 769571df..68d3f334 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,34 @@ ## Installation ```groovy -compile 'ru.noties:markwon:1.0.5' -compile 'ru.noties:markwon-image-loader:1.0.5' // optional -compile 'ru.noties:markwon-view:1.0.5' // optional +compile 'ru.noties:markwon:1.0.6' +compile 'ru.noties:markwon-image-loader:1.0.6' // optional +compile 'ru.noties:markwon-view:1.0.6' // optional ``` +### Snapshot +![markwon-snapshot](https://img.shields.io/nexus/s/https/oss.sonatype.org/ru.noties/markwon.svg?label=markwon) + +In order to use latest `SNAPSHOT` version add snapshot repository to your root project's `build.gradle` file: + +```groovy +allprojects { + repositories { + jcenter() + google() + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + } +} +``` + +and then in your module `build.gradle`: + +```groovy +implementation 'ru.noties:markwon:1.0.6-SNAPSHOT' +``` + +Please note that `markwon-image-loader` and `markwon-view` are also present in `SNAPSHOT` repository and share the same version as main `markwon` artifact. + ## Supported markdown features: * Emphasis (`*`, `_`) * Strong emphasis (`**`, `__`) @@ -111,6 +134,11 @@ Markwon.scheduleDrawables(textView); Markwon.scheduleTableRows(textView); ``` +Please note that if you are having trouble with `LinkMovementMethod` you can use +`Markwon.setText(textView, markdown, movementMethod)` method (`@since 1.0.6`) to specify _no_ movement +method (aka `null`) or own implementation. As an alternative to the system `LinkMovementMethod` +you can use [Better-Link-Movement-Method][better-link-movement-method]. + Please refer to [SpannableConfiguration] document for more info --- @@ -269,6 +297,10 @@ Underscores (`_`) --- +## Applications using Markwon + +* [FairNote Notepad](https://play.google.com/store/apps/details?id=com.rgiskard.fairnote) + ## License @@ -292,6 +324,7 @@ Underscores (`_`) [commonmark-java]: https://github.com/atlassian/commonmark-java/blob/master/README.md [cheatsheet]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet [SpannableConfiguration]: ./docs/SpannableConfiguration.md +[better-link-movement-method]: https://github.com/saket/Better-Link-Movement-Method [arbitrary case-insensitive reference text]: https://www.mozilla.org [1]: http://slashdot.org diff --git a/app/build.gradle b/app/build.gradle index 286e6bb9..9d5e07df 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,6 +31,7 @@ dependencies { implementation project(':library-image-loader') implementation 'ru.noties:debug:3.0.0@jar' + implementation 'me.saket:better-link-movement-method:2.2.0' implementation OK_HTTP diff --git a/app/src/main/java/ru/noties/markwon/MainActivity.java b/app/src/main/java/ru/noties/markwon/MainActivity.java index 8b5b10dc..11212635 100644 --- a/app/src/main/java/ru/noties/markwon/MainActivity.java +++ b/app/src/main/java/ru/noties/markwon/MainActivity.java @@ -4,11 +4,14 @@ import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.view.View; import android.widget.TextView; import javax.inject.Inject; +import me.saket.bettermovementmethod.BetterLinkMovementMethod; import ru.noties.debug.Debug; public class MainActivity extends Activity { @@ -64,7 +67,7 @@ public class MainActivity extends Activity { markdownRenderer.render(MainActivity.this, uri(), text, new MarkdownRenderer.MarkdownReadyListener() { @Override public void onMarkdownReady(CharSequence markdown) { - Markwon.setText(textView, markdown); + Markwon.setText(textView, markdown, BetterLinkMovementMethod.getInstance()); Views.setVisible(progress, false); } }); @@ -72,6 +75,7 @@ public class MainActivity extends Activity { }); } + @NonNull private AppBarItem.State appBarState() { final String title; @@ -100,6 +104,7 @@ public class MainActivity extends Activity { } } + @Nullable private Uri uri() { final Intent intent = getIntent(); return intent != null diff --git a/gradle.properties b/gradle.properties index b998b4c3..f3424164 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.configureondemand=true android.enableBuildCache=true android.buildCacheDir=build/pre-dex-cache -VERSION_NAME=1.0.5 +VERSION_NAME=1.0.6 GROUP=ru.noties POM_DESCRIPTION=Markwon diff --git a/library/src/main/java/ru/noties/markwon/Markwon.java b/library/src/main/java/ru/noties/markwon/Markwon.java index 77b397d3..01273b78 100644 --- a/library/src/main/java/ru/noties/markwon/Markwon.java +++ b/library/src/main/java/ru/noties/markwon/Markwon.java @@ -2,7 +2,9 @@ package ru.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.method.LinkMovementMethod; +import android.text.method.MovementMethod; import android.widget.TextView; import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension; @@ -67,20 +69,39 @@ public abstract class Markwon { /** * Helper method to apply parsed markdown. + *

+ * Since 1.0.6 redirects it\'s call to {@link #setText(TextView, CharSequence, MovementMethod)} + * with LinkMovementMethod as an argument to preserve current API. * * @param view {@link TextView} to set markdown into * @param text parsed markdown - * @see #scheduleDrawables(TextView) - * @see #scheduleTableRows(TextView) + * @see #setText(TextView, CharSequence, MovementMethod) * @since 1.0.0 */ public static void setText(@NonNull TextView view, CharSequence text) { + setText(view, text, LinkMovementMethod.getInstance()); + } + + /** + * Helper method to apply parsed markdown with additional argument of a MovementMethod. Used + * to workaround problems that occur when using system LinkMovementMethod (for example: + * https://issuetracker.google.com/issues/37068143). As a better alternative to it consider + * using: https://github.com/saket/Better-Link-Movement-Method + * + * @param view TextView to set markdown into + * @param text parsed markdown + * @param movementMethod an implementation if MovementMethod or null + * @see #scheduleDrawables(TextView) + * @see #scheduleTableRows(TextView) + * @since 1.0.6 + */ + public static void setText(@NonNull TextView view, CharSequence text, @Nullable MovementMethod movementMethod) { unscheduleDrawables(view); unscheduleTableRows(view); // update movement method (for links to be clickable) - view.setMovementMethod(LinkMovementMethod.getInstance()); + view.setMovementMethod(movementMethod); view.setText(text); // schedule drawables (dynamic drawables that can change bounds/animate will be correctly updated) diff --git a/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java b/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java index 3b9332bd..3aa18cb1 100644 --- a/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java +++ b/library/src/main/java/ru/noties/markwon/SpannableConfiguration.java @@ -3,8 +3,8 @@ package ru.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; -import ru.noties.markwon.renderer.html.ImageSizeResolver; -import ru.noties.markwon.renderer.html.ImageSizeResolverDef; +import ru.noties.markwon.renderer.ImageSizeResolver; +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; @@ -30,6 +30,7 @@ public class SpannableConfiguration { private final LinkSpan.Resolver linkResolver; private final UrlProcessor urlProcessor; private final SpannableHtmlParser htmlParser; + private final ImageSizeResolver imageSizeResolver; private SpannableConfiguration(@NonNull Builder builder) { this.theme = builder.theme; @@ -38,6 +39,7 @@ public class SpannableConfiguration { this.linkResolver = builder.linkResolver; this.urlProcessor = builder.urlProcessor; this.htmlParser = builder.htmlParser; + this.imageSizeResolver = builder.imageSizeResolver; } @NonNull @@ -70,6 +72,11 @@ public class SpannableConfiguration { return htmlParser; } + @NonNull + public ImageSizeResolver imageSizeResolver() { + return imageSizeResolver; + } + @SuppressWarnings("unused") public static class Builder { @@ -154,12 +161,11 @@ public class SpannableConfiguration { urlProcessor = new UrlProcessorNoOp(); } + if (imageSizeResolver == null) { + imageSizeResolver = new ImageSizeResolverDef(); + } + if (htmlParser == null) { - - if (imageSizeResolver == null) { - imageSizeResolver = new ImageSizeResolverDef(); - } - htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor, linkResolver, imageSizeResolver); } diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java b/library/src/main/java/ru/noties/markwon/renderer/ImageSize.java similarity index 78% rename from library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java rename to library/src/main/java/ru/noties/markwon/renderer/ImageSize.java index f65144ab..074ce880 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSize.java +++ b/library/src/main/java/ru/noties/markwon/renderer/ImageSize.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.renderer.html; +package ru.noties.markwon.renderer; import android.support.annotation.Nullable; @@ -34,4 +34,12 @@ public class ImageSize { this.width = width; this.height = height; } + + @Override + public String toString() { + return "ImageSize{" + + "width=" + width + + ", height=" + height + + '}'; + } } diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java b/library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolver.java similarity index 95% rename from library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java rename to library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolver.java index 41574bb7..a7241914 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolver.java +++ b/library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolver.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.renderer.html; +package ru.noties.markwon.renderer; import android.graphics.Rect; import android.support.annotation.NonNull; diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java b/library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolverDef.java similarity index 98% rename from library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java rename to library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolverDef.java index b7eb1fc9..60710f71 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/html/ImageSizeResolverDef.java +++ b/library/src/main/java/ru/noties/markwon/renderer/ImageSizeResolverDef.java @@ -1,4 +1,4 @@ -package ru.noties.markwon.renderer.html; +package ru.noties.markwon.renderer; import android.graphics.Rect; import android.support.annotation.NonNull; diff --git a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java index 31195a4c..ceb22ef0 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java +++ b/library/src/main/java/ru/noties/markwon/renderer/SpannableMarkdownVisitor.java @@ -438,7 +438,9 @@ public class SpannableMarkdownVisitor extends AbstractVisitor { configuration.theme(), new AsyncDrawable( destination, - configuration.asyncDrawableLoader() + configuration.asyncDrawableLoader(), + configuration.imageSizeResolver(), + null ), AsyncDrawableSpan.ALIGN_BOTTOM, link diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java b/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java index 54a5086f..1d5968b7 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java +++ b/library/src/main/java/ru/noties/markwon/renderer/html/ImageProviderImpl.java @@ -11,6 +11,8 @@ import java.util.HashMap; import java.util.Map; import ru.noties.markwon.UrlProcessor; +import ru.noties.markwon.renderer.ImageSize; +import ru.noties.markwon.renderer.ImageSizeResolver; import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawableSpan; import ru.noties.markwon.spans.SpannableTheme; diff --git a/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java b/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java index 6423e1f9..3d7236a9 100644 --- a/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java +++ b/library/src/main/java/ru/noties/markwon/renderer/html/SpannableHtmlParser.java @@ -13,6 +13,8 @@ import java.util.Map; import ru.noties.markwon.LinkResolverDef; import ru.noties.markwon.UrlProcessor; import ru.noties.markwon.UrlProcessorNoOp; +import ru.noties.markwon.renderer.ImageSizeResolver; +import ru.noties.markwon.renderer.ImageSizeResolverDef; import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.LinkSpan; import ru.noties.markwon.spans.SpannableTheme; diff --git a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java index 705b666f..15ae4483 100644 --- a/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java +++ b/library/src/main/java/ru/noties/markwon/spans/AsyncDrawable.java @@ -10,8 +10,8 @@ import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import ru.noties.markwon.renderer.html.ImageSize; -import ru.noties.markwon.renderer.html.ImageSizeResolver; +import ru.noties.markwon.renderer.ImageSize; +import ru.noties.markwon.renderer.ImageSizeResolver; public class AsyncDrawable extends Drawable { @@ -33,6 +33,10 @@ public class AsyncDrawable extends Drawable { private int canvasWidth; private float textSize; + /** + * @deprecated 1.0.6 markdown images are also processed with {@link ImageSizeResolver} + */ + @Deprecated public AsyncDrawable(@NonNull String destination, @NonNull Loader loader) { this(destination, loader, null, null); } @@ -176,8 +180,7 @@ public class AsyncDrawable extends Drawable { final Rect rect; - if (imageSizeResolver == null - || imageSize == null) { + if (imageSizeResolver == null) { // @since 1.0.5 final Rect bounds = result.getBounds(); diff --git a/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java b/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java index 7beda477..368f13a9 100644 --- a/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java +++ b/library/src/main/java/ru/noties/markwon/spans/BulletListItemSpan.java @@ -48,12 +48,15 @@ public class BulletListItemSpan implements LeadingMarginSpan { try { final int width = theme.getBlockMargin(); - final int height = bottom - top; - final int side = theme.getBulletWidth(bottom - top); + // @since 1.0.6 we no longer rely on (bottom-top) calculation in order to detect line height + // it lead to bad rendering as first & last lines received different results even + // if text size is the same (first line received greater amount and bottom line -> less) + final int textLineHeight = (int) (paint.descent() - paint.ascent() + .5F); + + final int side = theme.getBulletWidth(textLineHeight); final int marginLeft = (width - side) / 2; - final int marginTop = (height - side) / 2; // in order to support RTL final int l; @@ -64,7 +67,8 @@ public class BulletListItemSpan implements LeadingMarginSpan { l = Math.min(left, right); r = Math.max(left, right); } - final int t = top + marginTop; + + final int t = baseline + (int) ((paint.descent() + paint.ascent()) / 2.F + .5F) - (side / 2); final int b = t + side; if (level == 0