From cb66618d3a4a5255b45e6415a26d11e365400322 Mon Sep 17 00:00:00 2001
From: Dimitry <noties@users.noreply.github.com>
Date: Tue, 26 Jun 2018 10:50:56 +0200
Subject: [PATCH] V1.0.6 (#46)

* Fix bullet list item size (depend on text size and not top-bottom arguments)

* Add SNAPSHOT publishing

* Add ability to specify MovementMethod when applying markdown to a TextView

* Add information about new method signature to README (Markwon.setText)

* Fix README links reference

* Add new section to README (applications using markwon)

* Markdown images size is also resolved via ImageSizeResolver
---
 README.md                                     | 39 +++++++++++++++++--
 app/build.gradle                              |  1 +
 .../java/ru/noties/markwon/MainActivity.java  |  7 +++-
 gradle.properties                             |  2 +-
 .../main/java/ru/noties/markwon/Markwon.java  | 27 +++++++++++--
 .../markwon/SpannableConfiguration.java       | 20 ++++++----
 .../renderer/{html => }/ImageSize.java        | 10 ++++-
 .../{html => }/ImageSizeResolver.java         |  2 +-
 .../{html => }/ImageSizeResolverDef.java      |  2 +-
 .../renderer/SpannableMarkdownVisitor.java    |  4 +-
 .../renderer/html/ImageProviderImpl.java      |  2 +
 .../renderer/html/SpannableHtmlParser.java    |  2 +
 .../noties/markwon/spans/AsyncDrawable.java   | 11 ++++--
 .../markwon/spans/BulletListItemSpan.java     | 12 ++++--
 14 files changed, 114 insertions(+), 27 deletions(-)
 rename library/src/main/java/ru/noties/markwon/renderer/{html => }/ImageSize.java (78%)
 rename library/src/main/java/ru/noties/markwon/renderer/{html => }/ImageSizeResolver.java (95%)
 rename library/src/main/java/ru/noties/markwon/renderer/{html => }/ImageSizeResolverDef.java (98%)

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.
+     * <p>
+     * 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