diff --git a/build.gradle b/build.gradle index a7574d80..f34a6c05 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.4.1' classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' } } @@ -29,8 +29,8 @@ task clean(type: Delete) { delete rootProject.buildDir } -task wrapper(type: Wrapper) { - gradleVersion '4.10.2' +wrapper { + gradleVersion '5.1.1' distributionType 'all' } @@ -72,7 +72,8 @@ ext { 'debug' : 'ru.noties:debug:3.0.0@jar', 'adapt' : 'ru.noties:adapt:1.1.0', 'dagger' : "com.google.dagger:dagger:$daggerVersion", - 'picasso' : "com.squareup.picasso:picasso:2.71828" + 'picasso' : 'com.squareup.picasso:picasso:2.71828', + 'glide' : 'com.github.bumptech.glide:glide:4.9.0' ] deps['annotationProcessor'] = [ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 758de960..87b738cb 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d76b502e..c4486d47 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d5..af6708ff 100755 --- a/gradlew +++ b/gradlew @@ -28,7 +28,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" diff --git a/gradlew.bat b/gradlew.bat index e95643d6..0f8d5937 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome diff --git a/markwon-image-glide/build.gradle b/markwon-image-glide/build.gradle new file mode 100644 index 00000000..a9d3ef66 --- /dev/null +++ b/markwon-image-glide/build.gradle @@ -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['glide'] +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-image-glide/gradle.properties b/markwon-image-glide/gradle.properties new file mode 100644 index 00000000..8878f2a3 --- /dev/null +++ b/markwon-image-glide/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Image Glide +POM_ARTIFACT_ID=image-glide +POM_DESCRIPTION=Markwon image loading module (based on Glide library) +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-glide/src/main/AndroidManifest.xml b/markwon-image-glide/src/main/AndroidManifest.xml new file mode 100644 index 00000000..806be809 --- /dev/null +++ b/markwon-image-glide/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java b/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java new file mode 100644 index 00000000..2afa28f7 --- /dev/null +++ b/markwon-image-glide/src/main/java/ru/noties/markwon/image/glide/GlideImagesPlugin.java @@ -0,0 +1,189 @@ +package ru.noties.markwon.image.glide; + +import android.content.Context; +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.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.RequestManager; +import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.target.Target; +import com.bumptech.glide.request.transition.Transition; + +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 GlideImagesPlugin extends AbstractMarkwonPlugin { + + public interface GlideStore { + + @NonNull + RequestBuilder load(@NonNull AsyncDrawable drawable); + + void cancel(@NonNull Target target); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull final Context context) { + return create(new GlideStore() { + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + return Glide.with(context) + .load(drawable.getDestination()); + } + + @Override + public void cancel(@NonNull Target target) { + Glide.with(context) + .clear(target); + } + }); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull final RequestManager requestManager) { + return create(new GlideStore() { + @NonNull + @Override + public RequestBuilder load(@NonNull AsyncDrawable drawable) { + return requestManager.load(drawable.getDestination()); + } + + @Override + public void cancel(@NonNull Target target) { + requestManager.clear(target); + } + }); + } + + @NonNull + public static GlideImagesPlugin create(@NonNull GlideStore glideStore) { + return new GlideImagesPlugin(glideStore); + } + + private final GlideAsyncDrawableLoader glideAsyncDrawableLoader; + + @SuppressWarnings("WeakerAccess") + GlideImagesPlugin(@NonNull GlideStore glideStore) { + this.glideAsyncDrawableLoader = new GlideAsyncDrawableLoader(glideStore); + } + + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Image.class, new ImageSpanFactory()); + } + + @Override + public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) { + builder.asyncDrawableLoader(glideAsyncDrawableLoader); + } + + @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 GlideAsyncDrawableLoader extends AsyncDrawableLoader { + + private final GlideStore glideStore; + private final Map> cache = new HashMap<>(2); + + GlideAsyncDrawableLoader(@NonNull GlideStore glideStore) { + this.glideStore = glideStore; + } + + @Override + public void load(@NonNull AsyncDrawable drawable) { + final Target target = new AsyncDrawableTarget(drawable); + cache.put(drawable, target); + glideStore.load(drawable) + .into(target); + } + + @Override + public void cancel(@NonNull AsyncDrawable drawable) { + final Target target = cache.remove(drawable); + if (target != null) { + glideStore.cancel(target); + } + } + + @Nullable + @Override + public Drawable placeholder(@NonNull AsyncDrawable drawable) { + return null; + } + + private class AsyncDrawableTarget extends CustomTarget { + + private final AsyncDrawable drawable; + + AsyncDrawableTarget(@NonNull AsyncDrawable drawable) { + this.drawable = drawable; + } + + @Override + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + if (cache.remove(drawable) != null) { + if (drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(resource); + drawable.setResult(resource); + } + } + } + + @Override + public void onLoadStarted(@Nullable Drawable placeholder) { + if (placeholder != null + && drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(placeholder); + drawable.setResult(placeholder); + } + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + if (cache.remove(drawable) != null) { + if (errorDrawable != null + && drawable.isAttached()) { + DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable); + drawable.setResult(errorDrawable); + } + } + } + + @Override + public void onLoadCleared(@Nullable Drawable placeholder) { + // we won't be checking if target is still present as cancellation + // must remove target anyway + if (drawable.isAttached()) { + drawable.clearResult(); + } + } + } + } +} diff --git a/markwon-image-picasso/gradle.properties b/markwon-image-picasso/gradle.properties index 70a5e05a..d811058b 100644 --- a/markwon-image-picasso/gradle.properties +++ b/markwon-image-picasso/gradle.properties @@ -1,4 +1,4 @@ -POM_NAME=Image +POM_NAME=Image Picasso POM_ARTIFACT_ID=image-picasso POM_DESCRIPTION=Markwon image loading module (based on Picasso library) POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java index 5eeb5b6d..7bb37c1d 100644 --- a/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java +++ b/markwon-image-picasso/src/main/java/ru/noties/markwon/image/picasso/PicassoImagesPlugin.java @@ -70,6 +70,7 @@ public class PicassoImagesPlugin extends AbstractMarkwonPlugin { private final PicassoAsyncDrawableLoader picassoAsyncDrawableLoader; + @SuppressWarnings("WeakerAccess") PicassoImagesPlugin(@NonNull PicassoStore picassoStore) { this.picassoAsyncDrawableLoader = new PicassoAsyncDrawableLoader(picassoStore); } diff --git a/sample/build.gradle b/sample/build.gradle index 86934833..4bde062b 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -44,6 +44,11 @@ dependencies { implementation project(':markwon-recycler') implementation project(':markwon-recycler-table') + // these are for glide + implementation 'com.android.support:animated-vector-drawable:28.0.0' + implementation 'com.android.support:support-fragment:28.0.0' + + implementation project(':markwon-image-glide') implementation project(':markwon-image-picasso') deps.with { diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index c187ea93..72409a5f 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -32,6 +32,7 @@ import ru.noties.markwon.MarkwonVisitor; import ru.noties.markwon.core.CorePlugin; import ru.noties.markwon.html.HtmlPlugin; import ru.noties.markwon.image.AsyncDrawable; +import ru.noties.markwon.image.glide.GlideImagesPlugin; import ru.noties.markwon.image.picasso.PicassoImagesPlugin; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; @@ -85,7 +86,8 @@ public class RecyclerActivity extends Activity { // .addSchemeHandler(OkHttpNetworkSchemeHandler.create()) // .addMediaDecoder(SvgMediaDecoder.create()); // })) - .usePlugin(PicassoImagesPlugin.create(context)) +// .usePlugin(PicassoImagesPlugin.create(context)) + .usePlugin(GlideImagesPlugin.create(context)) // important to use TableEntryPlugin instead of TablePlugin .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) diff --git a/settings.gradle b/settings.gradle index e5b09011..da0bcd9e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,6 +7,7 @@ include ':app', ':sample', ':markwon-ext-tasklist', ':markwon-html', ':markwon-image', + ':markwon-image-glide', ':markwon-image-picasso', ':markwon-recycler', ':markwon-recycler-table',