Convert ContactPictureLoader to Kotlin

This commit is contained in:
cketti 2018-07-19 15:58:57 +02:00
parent 2dd7d00f8d
commit 9ada669e0b
2 changed files with 126 additions and 166 deletions

View file

@ -12,6 +12,6 @@ public class ContactPicture {
public static ContactPictureLoader getContactPictureLoader(Context context) {
ContactLetterBitmapCreator contactLetterBitmapCreator = DI.get(ContactLetterBitmapCreator.class);
return new ContactPictureLoader(context, contactLetterBitmapCreator);
return new ContactPictureLoader(context.getApplicationContext(), contactLetterBitmapCreator);
}
}

View file

@ -1,229 +1,189 @@
package com.fsck.k9.contacts;
package com.fsck.k9.contacts
import java.io.IOException;
import java.util.Locale;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.resource.bitmap.BitmapEncoder;
import com.bumptech.glide.load.resource.bitmap.BitmapResource;
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
import com.bumptech.glide.load.resource.transcode.BitmapToGlideDrawableTranscoder;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.mail.Address;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.net.Uri
import android.support.annotation.WorkerThread
import android.widget.ImageView
import com.bumptech.glide.Glide
import com.bumptech.glide.Priority
import com.bumptech.glide.load.ResourceDecoder
import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.Resource
import com.bumptech.glide.load.model.ModelLoader
import com.bumptech.glide.load.resource.bitmap.BitmapEncoder
import com.bumptech.glide.load.resource.bitmap.BitmapResource
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder
import com.bumptech.glide.load.resource.drawable.GlideDrawable
import com.bumptech.glide.load.resource.file.FileToStreamDecoder
import com.bumptech.glide.load.resource.transcode.BitmapToGlideDrawableTranscoder
import com.bumptech.glide.request.FutureTarget
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.fsck.k9.helper.Contacts
import com.fsck.k9.mail.Address
import com.fsck.k9.view.RecipientSelectView.Recipient
import java.util.Locale
public class ContactPictureLoader {
/**
* Resize the pictures to the following value (device-independent pixels).
*/
private static final int PICTURE_SIZE = 40;
class ContactPictureLoader(
private val context: Context,
private val contactLetterBitmapCreator: ContactLetterBitmapCreator
) {
private val contactsHelper: Contacts = Contacts.getInstance(context)
private val pictureSizeInPx: Int = PICTURE_SIZE.toDip(context)
private final Context context;
private final ContactLetterBitmapCreator contactLetterBitmapCreator;
private Contacts mContactsHelper;
private int mPictureSizeInPx;
public ContactPictureLoader(Context context, ContactLetterBitmapCreator contactLetterBitmapCreator) {
this.context = context.getApplicationContext();
this.contactLetterBitmapCreator = contactLetterBitmapCreator;
mContactsHelper = Contacts.getInstance(this.context);
Resources resources = context.getResources();
float scale = resources.getDisplayMetrics().density;
mPictureSizeInPx = (int) (PICTURE_SIZE * scale);
fun loadContactPicture(address: Address, imageView: ImageView) {
val photoUri = contactsHelper.getPhotoUri(address.address)
loadContactPicture(photoUri, address, imageView)
}
public void loadContactPicture(final Address address, final ImageView imageView) {
Uri photoUri = mContactsHelper.getPhotoUri(address.getAddress());
loadContactPicture(photoUri, address, imageView);
fun loadContactPicture(recipient: Recipient, imageView: ImageView) {
loadContactPicture(recipient.photoThumbnailUri, recipient.address, imageView)
}
public void loadContactPicture(Recipient recipient, ImageView imageView) {
loadContactPicture(recipient.photoThumbnailUri, recipient.address, imageView);
}
private void loadFallbackPicture(Address address, ImageView imageView) {
Context context = imageView.getContext();
private fun loadFallbackPicture(address: Address, imageView: ImageView) {
val context = imageView.context
Glide.with(context)
.using(new FallbackGlideModelLoader(), FallbackGlideParams.class)
.from(FallbackGlideParams.class)
.as(Bitmap.class)
.transcode(new BitmapToGlideDrawableTranscoder(context), GlideDrawable.class)
.decoder(new FallbackGlideBitmapDecoder(context))
.encoder(new BitmapEncoder(Bitmap.CompressFormat.PNG, 0))
.cacheDecoder(new FileToStreamDecoder<>(new StreamBitmapDecoder(context)))
.using(FallbackGlideModelLoader(), FallbackGlideParams::class.java)
.from(FallbackGlideParams::class.java)
.`as`(Bitmap::class.java)
.transcode(BitmapToGlideDrawableTranscoder(context), GlideDrawable::class.java)
.decoder(FallbackGlideBitmapDecoder())
.encoder(BitmapEncoder(Bitmap.CompressFormat.PNG, 0))
.cacheDecoder(FileToStreamDecoder(StreamBitmapDecoder(context)))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(new FallbackGlideParams(address))
.load(FallbackGlideParams(address))
// for some reason, following 2 lines fix loading issues.
.dontAnimate()
.override(mPictureSizeInPx, mPictureSizeInPx)
.into(imageView);
.override(pictureSizeInPx, pictureSizeInPx)
.into(imageView)
}
private void loadContactPicture(Uri photoUri, final Address address, final ImageView imageView) {
private fun loadContactPicture(photoUri: Uri?, address: Address, imageView: ImageView) {
if (photoUri != null) {
RequestListener<Uri, GlideDrawable> noPhotoListener = new RequestListener<Uri, GlideDrawable>() {
@Override
public boolean onException(Exception e, Uri model, Target<GlideDrawable> target,
boolean isFirstResource) {
loadFallbackPicture(address, imageView);
return true;
val noPhotoListener = object : RequestListener<Uri, GlideDrawable> {
override fun onException(
e: Exception,
model: Uri,
target: Target<GlideDrawable>,
isFirstResource: Boolean
): Boolean {
loadFallbackPicture(address, imageView)
return true
}
@Override
public boolean onResourceReady(GlideDrawable resource, Uri model,
Target<GlideDrawable> target,
boolean isFromMemoryCache, boolean isFirstResource) {
return false;
override fun onResourceReady(
resource: GlideDrawable,
model: Uri,
target: Target<GlideDrawable>,
isFromMemoryCache: Boolean,
isFirstResource: Boolean
): Boolean {
return false
}
};
}
Glide.with(imageView.getContext())
Glide.with(imageView.context)
.load(photoUri)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.listener(noPhotoListener)
// for some reason, following 2 lines fix loading issues.
.dontAnimate()
.override(mPictureSizeInPx, mPictureSizeInPx)
.into(imageView);
.override(pictureSizeInPx, pictureSizeInPx)
.into(imageView)
} else {
loadFallbackPicture(address, imageView);
loadFallbackPicture(address, imageView)
}
}
public Bitmap loadContactPictureIcon(Recipient recipient) {
return loadContactPicture(recipient.photoThumbnailUri, recipient.address);
fun loadContactPictureIcon(recipient: Recipient): Bitmap? {
return loadContactPicture(recipient.photoThumbnailUri, recipient.address)
}
@WorkerThread
private Bitmap loadContactPicture(Uri photoUri, Address address) {
FutureTarget<Bitmap> bitmapTarget;
private fun loadContactPicture(photoUri: Uri?, address: Address): Bitmap? {
val bitmapTarget: FutureTarget<Bitmap>
if (photoUri != null) {
bitmapTarget = Glide.with(context)
.load(photoUri)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.dontAnimate()
.into(mPictureSizeInPx, mPictureSizeInPx);
.into(pictureSizeInPx, pictureSizeInPx)
} else {
bitmapTarget = Glide.with(context)
.using(new FallbackGlideModelLoader(), FallbackGlideParams.class)
.from(FallbackGlideParams.class)
.as(Bitmap.class)
.decoder(new FallbackGlideBitmapDecoder(context))
.encoder(new BitmapEncoder(CompressFormat.PNG, 0))
.cacheDecoder(new FileToStreamDecoder<>(new StreamBitmapDecoder(context)))
.using(FallbackGlideModelLoader(), FallbackGlideParams::class.java)
.from(FallbackGlideParams::class.java)
.`as`(Bitmap::class.java)
.decoder(FallbackGlideBitmapDecoder())
.encoder(BitmapEncoder(CompressFormat.PNG, 0))
.cacheDecoder(FileToStreamDecoder(StreamBitmapDecoder(context)))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(new FallbackGlideParams(address))
.load(FallbackGlideParams(address))
.dontAnimate()
.into(mPictureSizeInPx, mPictureSizeInPx);
.into(pictureSizeInPx, pictureSizeInPx)
}
return loadIgnoringErors(bitmapTarget);
return loadIgnoringErrors(bitmapTarget)
}
private class FallbackGlideBitmapDecoder implements ResourceDecoder<FallbackGlideParams, Bitmap> {
private final Context context;
private inner class FallbackGlideBitmapDecoder : ResourceDecoder<FallbackGlideParams, Bitmap> {
override fun decode(source: FallbackGlideParams, width: Int, height: Int): Resource<Bitmap> {
val pool = Glide.get(context).bitmapPool
val bitmap: Bitmap =
pool.getDirty(pictureSizeInPx, pictureSizeInPx, Bitmap.Config.ARGB_8888) ?:
Bitmap.createBitmap(pictureSizeInPx, pictureSizeInPx, Bitmap.Config.ARGB_8888)
FallbackGlideBitmapDecoder(Context context) {
this.context = context;
contactLetterBitmapCreator.drawBitmap(bitmap, pictureSizeInPx, source.address)
return BitmapResource.obtain(bitmap, pool)
}
@Override
public Resource<Bitmap> decode(FallbackGlideParams source, int width, int height) throws IOException {
BitmapPool pool = Glide.get(context).getBitmapPool();
Bitmap bitmap = pool.getDirty(mPictureSizeInPx, mPictureSizeInPx, Bitmap.Config.ARGB_8888);
if (bitmap == null) {
bitmap = Bitmap.createBitmap(mPictureSizeInPx, mPictureSizeInPx, Bitmap.Config.ARGB_8888);
}
Address address = source.address;
contactLetterBitmapCreator.drawBitmap(bitmap, mPictureSizeInPx, address);
return BitmapResource.obtain(bitmap, pool);
}
@Override
public String getId() {
return "fallback-photo";
override fun getId(): String {
return "fallback-photo"
}
}
private class FallbackGlideParams {
final Address address;
FallbackGlideParams(Address address) {
this.address = address;
}
public String getId() {
return String.format(Locale.ROOT, "%s-%s", address.getAddress(), address.getPersonal());
}
private inner class FallbackGlideParams(val address: Address) {
val id: String
get() = String.format(Locale.ROOT, "%s-%s", address.address, address.personal)
}
private class FallbackGlideModelLoader implements ModelLoader<FallbackGlideParams, FallbackGlideParams> {
@Override
public DataFetcher<FallbackGlideParams> getResourceFetcher(final FallbackGlideParams model, int width,
int height) {
return new DataFetcher<FallbackGlideParams>() {
@Override
public FallbackGlideParams loadData(Priority priority) throws Exception {
return model;
}
@Override
public void cleanup() {
}
@Override
public String getId() {
return model.getId();
}
@Override
public void cancel() {
}
};
private inner class FallbackGlideModelLoader : ModelLoader<FallbackGlideParams, FallbackGlideParams> {
override fun getResourceFetcher(
model: FallbackGlideParams,
width: Int,
height: Int
): DataFetcher<FallbackGlideParams> = object : DataFetcher<FallbackGlideParams> {
override fun loadData(priority: Priority): FallbackGlideParams = model
override fun getId(): String = model.id
override fun cleanup() = Unit
override fun cancel() = Unit
}
}
@WorkerThread
@Nullable
private <T> T loadIgnoringErors(FutureTarget<T> target) {
try {
return target.get();
} catch (Exception e) {
return null;
private fun <T> loadIgnoringErrors(target: FutureTarget<T>): T? {
return try {
target.get()
} catch (e: Exception) {
null
}
}
private fun Int.toDip(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()
companion object {
/**
* Resize the pictures to the following value (device-independent pixels).
*/
private const val PICTURE_SIZE = 40
}
}