Merge pull request #174 from tylerbwong/image-coil

Add CoilImagesPlugin Module
This commit is contained in:
Dimitry 2019-11-14 15:18:20 +03:00 committed by GitHub
commit 6b9e79ce5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 255 additions and 1 deletions

View File

@ -72,7 +72,8 @@ ext {
'adapt' : 'io.noties:adapt:2.0.0', 'adapt' : 'io.noties:adapt:2.0.0',
'dagger' : "com.google.dagger:dagger:$daggerVersion", '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' 'glide' : 'com.github.bumptech.glide:glide:4.9.0',
'coil' : 'io.coil-kt:coil:0.8.0'
] ]
deps['annotationProcessor'] = [ deps['annotationProcessor'] = [

View File

@ -0,0 +1,35 @@
# Image Coil
<MavenBadge4 :artifact="'image-coil'" />
Image loading based on `Coil` library
```kotlin
val markwon = Markwon.builder(context)
// automatically create Coil instance
.usePlugin(CoilImagesPlugin.create(context))
// use supplied ImageLoader instance
.usePlugin(CoilImagesPlugin.create(
context,
ImageLoader(context) {
availableMemoryPercentage(0.5)
bitmapPoolPercentage(0.5)
crossfade(true)
}
))
// if you need more control
.usePlugin(CoilImagesPlugin.create(object : CoilImagesPlugin.CoilStore {
override fun load(drawable: AsyncDrawable): LoadRequest {
return LoadRequest(context, customImageLoader.defaults) {
data(drawable.destination)
crossfade(true)
transformations(CircleCropTransformation())
}
}
override cancel(disposable: RequestDisposable) {
disposable.dispose()
}
}, customImageLoader))
.build()
```

View File

@ -0,0 +1,3 @@
# Images (Coil)
https://noties.io/Markwon/docs/v4/image-coil/

View 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['coil']
}
registerArtifact(this)

View File

@ -0,0 +1,4 @@
POM_NAME=Image Coil
POM_ARTIFACT_ID=image-coil
POM_DESCRIPTION=Markwon image loading module (based on Coil library)
POM_PACKAGING=aar

View File

@ -0,0 +1 @@
<manifest package="io.noties.markwon.image.coil" />

View File

@ -0,0 +1,187 @@
package io.noties.markwon.image.coil;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Spanned;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.commonmark.node.Image;
import java.util.HashMap;
import java.util.Map;
import coil.Coil;
import coil.ImageLoader;
import coil.api.ImageLoaders;
import coil.request.LoadRequest;
import coil.request.RequestDisposable;
import coil.target.Target;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonSpansFactory;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.AsyncDrawableLoader;
import io.noties.markwon.image.AsyncDrawableScheduler;
import io.noties.markwon.image.DrawableUtils;
import io.noties.markwon.image.ImageSpanFactory;
/**
* @since 4.0.0
* @author Tyler Wong
*/
public class CoilImagesPlugin extends AbstractMarkwonPlugin {
public interface CoilStore {
@NonNull
LoadRequest load(@NonNull AsyncDrawable drawable);
void cancel(@NonNull RequestDisposable disposable);
}
@NonNull
public static CoilImagesPlugin create(@NonNull final Context context) {
return create(new CoilStore() {
@NonNull
@Override
public LoadRequest load(@NonNull AsyncDrawable drawable) {
return ImageLoaders.newLoadBuilder(Coil.loader(), context)
.data(drawable.getDestination())
.build();
}
@Override
public void cancel(@NonNull RequestDisposable disposable) {
disposable.dispose();
}
}, Coil.loader());
}
@NonNull
public static CoilImagesPlugin create(@NonNull final Context context,
@NonNull final ImageLoader imageLoader) {
return create(new CoilStore() {
@NonNull
@Override
public LoadRequest load(@NonNull AsyncDrawable drawable) {
return ImageLoaders.newLoadBuilder(imageLoader, context)
.data(drawable.getDestination())
.build();
}
@Override
public void cancel(@NonNull RequestDisposable disposable) {
disposable.dispose();
}
}, imageLoader);
}
@NonNull
public static CoilImagesPlugin create(@NonNull final CoilStore coilStore,
@NonNull final ImageLoader imageLoader) {
return new CoilImagesPlugin(coilStore, imageLoader);
}
private final CoilAsyncDrawableLoader coilAsyncDrawableLoader;
@SuppressWarnings("WeakerAccess")
CoilImagesPlugin(@NonNull CoilStore coilStore, @NonNull ImageLoader imageLoader) {
this.coilAsyncDrawableLoader = new CoilAsyncDrawableLoader(coilStore, imageLoader);
}
@Override
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
builder.setFactory(Image.class, new ImageSpanFactory());
}
@Override
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
builder.asyncDrawableLoader(coilAsyncDrawableLoader);
}
@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 CoilAsyncDrawableLoader extends AsyncDrawableLoader {
private final CoilStore coilStore;
private final ImageLoader imageLoader;
private final Map<AsyncDrawable, RequestDisposable> cache = new HashMap<>(2);
CoilAsyncDrawableLoader(@NonNull CoilStore coilStore, @NonNull ImageLoader imageLoader) {
this.coilStore = coilStore;
this.imageLoader = imageLoader;
}
@Override
public void load(@NonNull AsyncDrawable drawable) {
final Target target = new AsyncDrawableTarget(drawable);
LoadRequest request = coilStore.load(drawable).newBuilder()
.target(target)
.build();
RequestDisposable disposable = imageLoader.load(request);
cache.put(drawable, disposable);
}
@Override
public void cancel(@NonNull AsyncDrawable drawable) {
final RequestDisposable disposable = cache.remove(drawable);
if (disposable != null) {
coilStore.cancel(disposable);
}
}
@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 onSuccess(@NonNull Drawable loadedDrawable) {
if (cache.remove(drawable) != null) {
if (drawable.isAttached()) {
DrawableUtils.applyIntrinsicBoundsIfEmpty(loadedDrawable);
drawable.setResult(loadedDrawable);
}
}
}
@Override
public void onStart(@Nullable Drawable placeholder) {
if (placeholder != null && drawable.isAttached()) {
DrawableUtils.applyIntrinsicBoundsIfEmpty(placeholder);
drawable.setResult(placeholder);
}
}
@Override
public void onError(@Nullable Drawable errorDrawable) {
if (cache.remove(drawable) != null) {
if (errorDrawable != null && drawable.isAttached()) {
DrawableUtils.applyIntrinsicBoundsIfEmpty(errorDrawable);
drawable.setResult(errorDrawable);
}
}
}
}
}
}

View File

@ -82,6 +82,7 @@ public class RecyclerActivity extends Activity {
// })) // }))
.usePlugin(PicassoImagesPlugin.create(context)) .usePlugin(PicassoImagesPlugin.create(context))
// .usePlugin(GlideImagesPlugin.create(context)) // .usePlugin(GlideImagesPlugin.create(context))
// .usePlugin(CoilImagesPlugin.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())

View File

@ -8,6 +8,7 @@ include ':app', ':sample',
':markwon-ext-tasklist', ':markwon-ext-tasklist',
':markwon-html', ':markwon-html',
':markwon-image', ':markwon-image',
':markwon-image-coil',
':markwon-image-glide', ':markwon-image-glide',
':markwon-image-picasso', ':markwon-image-picasso',
':markwon-linkify', ':markwon-linkify',