Implement configuration for image loading

We support just two variables in the configuration: gravity and width.
Image will be place left, center or right aligned, and width will be
WRAP_CONTENT or MATCH_PARENT
This commit is contained in:
Daniel Leal 2017-12-19 19:18:31 +01:00
parent 23d7c09f27
commit a77c84a30c
3 changed files with 93 additions and 17 deletions

View File

@ -36,6 +36,7 @@ import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import pl.droidsonroids.gif.GifDrawable; import pl.droidsonroids.gif.GifDrawable;
import ru.noties.markwon.spans.AsyncDrawable; import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.configuration.image.ImageConfig;
public class AsyncDrawableLoader implements AsyncDrawable.Loader { public class AsyncDrawableLoader implements AsyncDrawable.Loader {
@ -58,6 +59,7 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
private final ExecutorService executorService; private final ExecutorService executorService;
private final Handler mainThread; private final Handler mainThread;
private final Drawable errorDrawable; private final Drawable errorDrawable;
private final ImageConfig imageConfig;
private final Map<String, Future<?>> requests; private final Map<String, Future<?>> requests;
@ -67,6 +69,7 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
this.executorService = builder.executorService; this.executorService = builder.executorService;
this.mainThread = new Handler(Looper.getMainLooper()); this.mainThread = new Handler(Looper.getMainLooper());
this.errorDrawable = builder.errorDrawable; this.errorDrawable = builder.errorDrawable;
this.imageConfig = builder.imageConfig;
this.requests = new HashMap<>(3); this.requests = new HashMap<>(3);
} }
@ -146,7 +149,7 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
public void run() { public void run() {
final AsyncDrawable asyncDrawable = reference.get(); final AsyncDrawable asyncDrawable = reference.get();
if (asyncDrawable != null && asyncDrawable.isAttached()) { if (asyncDrawable != null && asyncDrawable.isAttached()) {
asyncDrawable.setResult(out); asyncDrawable.setResult(out, imageConfig);
} }
} }
}); });
@ -345,6 +348,7 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
private Resources resources; private Resources resources;
private ExecutorService executorService; private ExecutorService executorService;
private Drawable errorDrawable; private Drawable errorDrawable;
private ImageConfig imageConfig;
public Builder client(@NonNull OkHttpClient client) { public Builder client(@NonNull OkHttpClient client) {
this.client = client; this.client = client;
@ -366,6 +370,11 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
return this; return this;
} }
public Builder imageConfig(ImageConfig imageConfig) {
this.imageConfig = imageConfig;
return this;
}
public AsyncDrawableLoader build() { public AsyncDrawableLoader build() {
if (client == null) { if (client == null) {
client = new OkHttpClient(); client = new OkHttpClient();
@ -377,6 +386,9 @@ public class AsyncDrawableLoader implements AsyncDrawable.Loader {
// we will use executor from okHttp // we will use executor from okHttp
executorService = client.dispatcher().executorService(); executorService = client.dispatcher().executorService();
} }
if(imageConfig == null){
imageConfig = new ImageConfig();
}
return new AsyncDrawableLoader(this); return new AsyncDrawableLoader(this);
} }
} }

View File

@ -12,25 +12,26 @@ import android.support.annotation.Nullable;
import ru.noties.markwon.renderer.html.ImageSize; import ru.noties.markwon.renderer.html.ImageSize;
import ru.noties.markwon.renderer.html.ImageSizeResolver; import ru.noties.markwon.renderer.html.ImageSizeResolver;
import ru.noties.markwon.spans.configuration.image.ImageConfig;
import ru.noties.markwon.spans.configuration.image.ImageGravity;
import ru.noties.markwon.spans.configuration.image.ImageWidth;
public class AsyncDrawable extends Drawable { public class AsyncDrawable extends Drawable {
public interface Loader {
void load(@NonNull String destination, @NonNull AsyncDrawable drawable);
void cancel(@NonNull String destination);
}
private final String destination; private final String destination;
private final Loader loader; private final Loader loader;
private final ImageSize imageSize; private final ImageSize imageSize;
private final ImageSizeResolver imageSizeResolver; private final ImageSizeResolver imageSizeResolver;
private Drawable result; private Drawable result;
private Callback callback; private Callback callback;
private int canvasWidth; private int canvasWidth;
private float textSize; private float textSize;
public AsyncDrawable(@NonNull String destination, @NonNull Loader loader) { public AsyncDrawable(@NonNull String destination, @NonNull Loader loader) {
@ -41,10 +42,10 @@ public class AsyncDrawable extends Drawable {
* @since 1.0.1 * @since 1.0.1
*/ */
public AsyncDrawable( public AsyncDrawable(
@NonNull String destination, @NonNull String destination,
@NonNull Loader loader, @NonNull Loader loader,
@Nullable ImageSizeResolver imageSizeResolver, @Nullable ImageSizeResolver imageSizeResolver,
@Nullable ImageSize imageSize @Nullable ImageSize imageSize
) { ) {
this.destination = destination; this.destination = destination;
this.loader = loader; this.loader = loader;
@ -91,7 +92,7 @@ public class AsyncDrawable extends Drawable {
} }
} }
public void setResult(@NonNull Drawable result) { public void setResult(@NonNull Drawable result, @NonNull ImageConfig imageConfig) {
// if we have previous one, detach it // if we have previous one, detach it
if (this.result != null) { if (this.result != null) {
@ -101,7 +102,7 @@ public class AsyncDrawable extends Drawable {
this.result = result; this.result = result;
this.result.setCallback(callback); this.result.setCallback(callback);
final Rect bounds = resolveBounds(); final Rect bounds = resolveBounds(imageConfig);
result.setBounds(bounds); result.setBounds(bounds);
setBounds(bounds); setBounds(bounds);
@ -168,17 +169,55 @@ public class AsyncDrawable extends Drawable {
} }
/** /**
* @param imageConfig
* @since 1.0.1 * @since 1.0.1
*/ */
@NonNull @NonNull
private Rect resolveBounds() { private Rect resolveBounds(@NonNull ImageConfig imageConfig) {
final Rect rect; final Rect rect;
if (imageSizeResolver == null if (imageSizeResolver == null
|| imageSize == null) { || imageSize == null) {
rect = result.getBounds(); rect = result.getBounds();
} else { } else {
rect = imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize); rect = imageSizeResolver.resolveImageSize(imageSize, result.getBounds(), canvasWidth, textSize);
} }
return rect; return adjustBounds(rect, imageConfig);
}
private Rect adjustBounds(Rect bounds, ImageConfig imageConfig) {
final ImageGravity gravity = imageConfig.getGravity();
final ImageWidth imageWidth = imageConfig.getImageWidth();
if (imageWidth == ImageWidth.MatchParent) {
final float aspectRatio = (float) bounds.width() / bounds.height();
bounds.left = 0;
bounds.right = canvasWidth;
bounds.bottom = (int) (bounds.top + bounds.height() * aspectRatio);
} else {
switch (gravity) {
case Left:
//left is unchanged
break;
case Right:
bounds.left = canvasWidth - bounds.width();
bounds.right = canvasWidth;
break;
case Center:
final int center = canvasWidth / 2;
final int imageRadius = bounds.width() / 2;
bounds.left = center - imageRadius;
bounds.right = center + imageRadius;
break;
}
}
return bounds;
}
public interface Loader {
void load(@NonNull String destination, @NonNull AsyncDrawable drawable);
void cancel(@NonNull String destination);
} }
} }

View File

@ -0,0 +1,25 @@
package ru.noties.markwon.spans.configuration.image
/**
* Configuration for images
*
* Can set two parameters: image width style and horizontal gravity
*
* @property imageWidth Width of the image to be displayed (WRAP_CONTENT or MATCH_PARENT)
* @property gravity Horizontal gravity (left, right or center)
*/
class ImageConfig @JvmOverloads constructor(
val imageWidth: ImageWidth = ImageWidth.Wrap,
val gravity: ImageGravity = ImageGravity.Left
)
enum class ImageGravity {
Left,
Center,
Right
}
enum class ImageWidth {
Wrap,
MatchParent
}