Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fc01899d8e | ||
![]() |
4f979ea4c6 | ||
![]() |
c210dc56ca | ||
![]() |
30294782cb | ||
![]() |
e6b283e243 | ||
![]() |
c20f1520ab | ||
![]() |
b30a1e10a8 | ||
![]() |
08507c8a92 |
@ -1,5 +1,6 @@
|
|||||||
# https://docs.travis-ci.com/user/languages/android/
|
# https://docs.travis-ci.com/user/languages/android/
|
||||||
language: android
|
language: android
|
||||||
|
dist: trusty
|
||||||
jdk: openjdk8
|
jdk: openjdk8
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ org.gradle.configureondemand=true
|
|||||||
android.enableBuildCache=true
|
android.enableBuildCache=true
|
||||||
android.buildCacheDir=build/pre-dex-cache
|
android.buildCacheDir=build/pre-dex-cache
|
||||||
|
|
||||||
VERSION_NAME=3.0.1
|
VERSION_NAME=3.1.0
|
||||||
|
|
||||||
GROUP=ru.noties.markwon
|
GROUP=ru.noties.markwon
|
||||||
POM_DESCRIPTION=Markwon markdown for Android
|
POM_DESCRIPTION=Markwon markdown for Android
|
||||||
|
@ -32,7 +32,7 @@ public class AsyncDrawable extends Drawable {
|
|||||||
public AsyncDrawable(
|
public AsyncDrawable(
|
||||||
@NonNull String destination,
|
@NonNull String destination,
|
||||||
@NonNull AsyncDrawableLoader loader,
|
@NonNull AsyncDrawableLoader loader,
|
||||||
@Nullable ImageSizeResolver imageSizeResolver,
|
@NonNull ImageSizeResolver imageSizeResolver,
|
||||||
@Nullable ImageSize imageSize
|
@Nullable ImageSize imageSize
|
||||||
) {
|
) {
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
@ -51,6 +51,45 @@ public class AsyncDrawable extends Drawable {
|
|||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ImageSize getImageSize() {
|
||||||
|
return imageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public ImageSizeResolver getImageSizeResolver() {
|
||||||
|
return imageSizeResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public boolean hasKnownDimentions() {
|
||||||
|
return canvasWidth > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #hasKnownDimentions()
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public int getLastKnownCanvasWidth() {
|
||||||
|
return canvasWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #hasKnownDimentions()
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public float getLastKnowTextSize() {
|
||||||
|
return textSize;
|
||||||
|
}
|
||||||
|
|
||||||
public Drawable getResult() {
|
public Drawable getResult() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -80,7 +119,7 @@ public class AsyncDrawable extends Drawable {
|
|||||||
result.setCallback(callback);
|
result.setCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
loader.load(destination, this);
|
loader.load(this);
|
||||||
} else {
|
} else {
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
|
||||||
@ -91,7 +130,7 @@ public class AsyncDrawable extends Drawable {
|
|||||||
((Animatable) result).stop();
|
((Animatable) result).stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loader.cancel(destination);
|
loader.cancel(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package ru.noties.markwon.image;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -36,10 +37,37 @@ public abstract class AsyncDrawableLoader {
|
|||||||
return new AsyncDrawableLoaderNoOp();
|
return new AsyncDrawableLoaderNoOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public abstract void load(@NonNull AsyncDrawable drawable);
|
||||||
|
|
||||||
public abstract void load(@NonNull String destination, @NonNull AsyncDrawable drawable);
|
/**
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public abstract void cancel(@NonNull AsyncDrawable drawable);
|
||||||
|
|
||||||
public abstract void cancel(@NonNull String destination);
|
/**
|
||||||
|
* @see #load(AsyncDrawable)
|
||||||
|
* @deprecated 3.1.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) {
|
||||||
|
load(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method is deprecated because cancellation won\'t work for markdown input
|
||||||
|
* with multiple images with the same source
|
||||||
|
*
|
||||||
|
* @deprecated 3.1.0
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void cancel(@NonNull String destination) {
|
||||||
|
Log.e("MARKWON-IL", "Image loading cancellation must be triggered " +
|
||||||
|
"by AsyncDrawable, please use #cancel(AsyncDrawable) method instead. " +
|
||||||
|
"No op, nothing is cancelled for destination: " + destination);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public abstract Drawable placeholder();
|
public abstract Drawable placeholder();
|
||||||
|
@ -4,12 +4,12 @@ import android.graphics.drawable.Drawable;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@ -23,10 +23,12 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
|
|||||||
private final MediaDecoder defaultMediaDecoder;
|
private final MediaDecoder defaultMediaDecoder;
|
||||||
private final DrawableProvider placeholderDrawableProvider;
|
private final DrawableProvider placeholderDrawableProvider;
|
||||||
private final DrawableProvider errorDrawableProvider;
|
private final DrawableProvider errorDrawableProvider;
|
||||||
|
private final Handler handler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
private final Handler mainThread;
|
|
||||||
|
|
||||||
private final Map<String, Future<?>> requests = new HashMap<>(2);
|
// @since 3.1.0 use a hash-map with an AsyncDrawable (allows multiple drawables
|
||||||
|
// referencing the same source)
|
||||||
|
private final Map<AsyncDrawable, Future<?>> requests = new HashMap<>(2);
|
||||||
|
|
||||||
AsyncDrawableLoaderImpl(@NonNull Builder builder) {
|
AsyncDrawableLoaderImpl(@NonNull Builder builder) {
|
||||||
this.executorService = builder.executorService;
|
this.executorService = builder.executorService;
|
||||||
@ -35,23 +37,27 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
|
|||||||
this.defaultMediaDecoder = builder.defaultMediaDecoder;
|
this.defaultMediaDecoder = builder.defaultMediaDecoder;
|
||||||
this.placeholderDrawableProvider = builder.placeholderDrawableProvider;
|
this.placeholderDrawableProvider = builder.placeholderDrawableProvider;
|
||||||
this.errorDrawableProvider = builder.errorDrawableProvider;
|
this.errorDrawableProvider = builder.errorDrawableProvider;
|
||||||
this.mainThread = new Handler(Looper.getMainLooper());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) {
|
public void load(@NonNull final AsyncDrawable drawable) {
|
||||||
// if drawable is not a link -> show loading placeholder...
|
final Future<?> future = requests.get(drawable);
|
||||||
requests.put(destination, execute(destination, drawable));
|
if (future == null) {
|
||||||
}
|
requests.put(drawable, execute(drawable));
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancel(@NonNull String destination) {
|
|
||||||
final Future<?> request = requests.remove(destination);
|
|
||||||
if (request != null) {
|
|
||||||
request.cancel(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel(@NonNull final AsyncDrawable drawable) {
|
||||||
|
|
||||||
|
final Future<?> future = requests.remove(drawable);
|
||||||
|
if (future != null) {
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.removeCallbacksAndMessages(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Drawable placeholder() {
|
public Drawable placeholder() {
|
||||||
@ -60,20 +66,10 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Future<?> execute(@NonNull final String destination, @NonNull AsyncDrawable drawable) {
|
@NonNull
|
||||||
|
private Future<?> execute(@NonNull final AsyncDrawable drawable) {
|
||||||
|
|
||||||
final WeakReference<AsyncDrawable> reference = new WeakReference<AsyncDrawable>(drawable);
|
final String destination = drawable.getDestination();
|
||||||
|
|
||||||
// todo: should we cancel pending request for the same destination?
|
|
||||||
// we _could_ but there is possibility that one resource is request in multiple places
|
|
||||||
|
|
||||||
// todo: error handing (simply applying errorDrawable is not a good solution
|
|
||||||
// as reason for an error is unclear (no scheme handler, no input data, error decoding, etc)
|
|
||||||
|
|
||||||
// todo: more efficient ImageMediaDecoder... BitmapFactory.decodeStream is a bit not optimal
|
|
||||||
// for big images for sure. We _could_ introduce internal Drawable that will check for
|
|
||||||
// image bounds (but we will need to cache inputStream in order to inspect and optimize
|
|
||||||
// input image...)
|
|
||||||
|
|
||||||
return executorService.submit(new Runnable() {
|
return executorService.submit(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -125,23 +121,18 @@ class AsyncDrawableLoaderImpl extends AsyncDrawableLoader {
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != null) {
|
final Drawable out = result;
|
||||||
final Drawable out = result;
|
|
||||||
mainThread.post(new Runnable() {
|
handler.postAtTime(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final boolean canDeliver = requests.remove(destination) != null;
|
if (requests.remove(drawable) != null) {
|
||||||
if (canDeliver) {
|
if (out != null && drawable.isAttached()) {
|
||||||
final AsyncDrawable asyncDrawable = reference.get();
|
drawable.setResult(out);
|
||||||
if (asyncDrawable != null && asyncDrawable.isAttached()) {
|
|
||||||
asyncDrawable.setResult(out);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else {
|
}, drawable, SystemClock.uptimeMillis());
|
||||||
requests.remove(destination);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import android.support.annotation.Nullable;
|
|||||||
|
|
||||||
class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader {
|
class AsyncDrawableLoaderNoOp extends AsyncDrawableLoader {
|
||||||
@Override
|
@Override
|
||||||
public void load(@NonNull String destination, @NonNull AsyncDrawable drawable) {
|
public void load(@NonNull AsyncDrawable drawable) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel(@NonNull String destination) {
|
public void cancel(@NonNull AsyncDrawable drawable) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,12 +80,8 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static String makeDestination(@NonNull String latex) {
|
|
||||||
return SCHEME + "://" + latex;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String SCHEME = "jlatexmath";
|
private static final String SCHEME = "jlatexmath";
|
||||||
|
private static final String SCHEME_START = SCHEME + "://";
|
||||||
private static final String CONTENT_TYPE = "text/jlatexmath";
|
private static final String CONTENT_TYPE = "text/jlatexmath";
|
||||||
|
|
||||||
private final Config config;
|
private final Config config;
|
||||||
@ -112,9 +108,11 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
final RenderProps renderProps = visitor.renderProps();
|
final RenderProps renderProps = visitor.renderProps();
|
||||||
|
|
||||||
ImageProps.DESTINATION.set(renderProps, makeDestination(latex));
|
ImageProps.DESTINATION.set(renderProps, SCHEME_START + latex);
|
||||||
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(renderProps, false);
|
ImageProps.REPLACEMENT_TEXT_IS_LINK.set(renderProps, false);
|
||||||
ImageProps.IMAGE_SIZE.set(renderProps, new ImageSize(new ImageSize.Dimension(100, "%"), null));
|
ImageProps.IMAGE_SIZE.set(
|
||||||
|
renderProps,
|
||||||
|
new ImageSize(new ImageSize.Dimension(100, "%"), null));
|
||||||
|
|
||||||
visitor.setSpansForNode(Image.class, length);
|
visitor.setSpansForNode(Image.class, length);
|
||||||
}
|
}
|
||||||
@ -132,7 +130,7 @@ public class JLatexMathPlugin extends AbstractMarkwonPlugin {
|
|||||||
ImageItem item = null;
|
ImageItem item = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final byte[] bytes = raw.substring(SCHEME.length()).getBytes("UTF-8");
|
final byte[] bytes = raw.substring(SCHEME_START.length()).getBytes("UTF-8");
|
||||||
item = new ImageItem(
|
item = new ImageItem(
|
||||||
CONTENT_TYPE,
|
CONTENT_TYPE,
|
||||||
new ByteArrayInputStream(bytes));
|
new ByteArrayInputStream(bytes));
|
||||||
|
@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
|
|||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import okhttp3.Call;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import ru.noties.markwon.AbstractMarkwonPlugin;
|
import ru.noties.markwon.AbstractMarkwonPlugin;
|
||||||
import ru.noties.markwon.image.AsyncDrawableLoader;
|
import ru.noties.markwon.image.AsyncDrawableLoader;
|
||||||
@ -28,20 +29,25 @@ public class OkHttpImagesPlugin extends AbstractMarkwonPlugin {
|
|||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static OkHttpImagesPlugin create(@NonNull OkHttpClient okHttpClient) {
|
public static OkHttpImagesPlugin create(@NonNull OkHttpClient okHttpClient) {
|
||||||
return new OkHttpImagesPlugin(okHttpClient);
|
return create((Call.Factory) okHttpClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final OkHttpClient client;
|
@NonNull
|
||||||
|
public static OkHttpImagesPlugin create(@NonNull Call.Factory callFactory) {
|
||||||
|
return new OkHttpImagesPlugin(callFactory);
|
||||||
|
}
|
||||||
|
|
||||||
OkHttpImagesPlugin(@NonNull OkHttpClient client) {
|
private final Call.Factory callFactory;
|
||||||
this.client = client;
|
|
||||||
|
OkHttpImagesPlugin(@NonNull Call.Factory callFactory) {
|
||||||
|
this.callFactory = callFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
public void configureImages(@NonNull AsyncDrawableLoader.Builder builder) {
|
||||||
builder.addSchemeHandler(
|
builder.addSchemeHandler(
|
||||||
Arrays.asList(NetworkSchemeHandler.SCHEME_HTTP, NetworkSchemeHandler.SCHEME_HTTPS),
|
Arrays.asList(NetworkSchemeHandler.SCHEME_HTTP, NetworkSchemeHandler.SCHEME_HTTPS),
|
||||||
new OkHttpSchemeHandler(client)
|
new OkHttpSchemeHandler(callFactory)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,9 @@ package ru.noties.markwon.image.okhttp;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import okhttp3.Call;
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
@ -18,10 +16,10 @@ class OkHttpSchemeHandler extends SchemeHandler {
|
|||||||
|
|
||||||
private static final String HEADER_CONTENT_TYPE = "Content-Type";
|
private static final String HEADER_CONTENT_TYPE = "Content-Type";
|
||||||
|
|
||||||
private final OkHttpClient client;
|
private final Call.Factory callFactory;
|
||||||
|
|
||||||
OkHttpSchemeHandler(@NonNull OkHttpClient client) {
|
OkHttpSchemeHandler(@NonNull Call.Factory callFactory) {
|
||||||
this.client = client;
|
this.callFactory = callFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -36,7 +34,7 @@ class OkHttpSchemeHandler extends SchemeHandler {
|
|||||||
|
|
||||||
Response response = null;
|
Response response = null;
|
||||||
try {
|
try {
|
||||||
response = client.newCall(request).execute();
|
response = callFactory.newCall(request).execute();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user