From eb15dc1260281f40c2801dbdaeb593a7b074bd28 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 8 Mar 2023 09:52:01 +0100 Subject: [PATCH] make avatar shape configurable (in code) --- .../android/ui/AvatarFetcher.java | 14 +++++++-- .../ui/graphics/drawable/AvatarDrawable.java | 29 ++++++++++++++----- .../android/xmpp/manager/AvatarManager.java | 8 ++++- app/src/main/res/layout/item_chatoverview.xml | 7 +++-- app/src/main/res/values/avatars.xml | 5 ++++ app/src/main/res/values/dimens.xml | 1 - 6 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 app/src/main/res/values/avatars.xml diff --git a/app/src/main/java/im/conversations/android/ui/AvatarFetcher.java b/app/src/main/java/im/conversations/android/ui/AvatarFetcher.java index 54d7e69d3..7608a5b5f 100644 --- a/app/src/main/java/im/conversations/android/ui/AvatarFetcher.java +++ b/app/src/main/java/im/conversations/android/ui/AvatarFetcher.java @@ -10,6 +10,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import im.conversations.android.R; import im.conversations.android.database.model.AddressWithName; import im.conversations.android.database.model.AvatarWithAccount; import im.conversations.android.ui.graphics.drawable.AvatarDrawable; @@ -59,9 +60,18 @@ public class AvatarFetcher { LOGGER.info("ImageView reference was gone after fetching avatar"); return; } + final var resources = imageView.getResources(); final var roundedBitmapDrawable = - RoundedBitmapDrawableFactory.create(imageView.getResources(), result); - roundedBitmapDrawable.setCircular(true); + RoundedBitmapDrawableFactory.create(resources, result); + final boolean circular = resources.getBoolean(R.bool.avatar_chat_overview_circular); + if (circular) { + roundedBitmapDrawable.setCircular(true); + } else { + final float radius = + resources.getDimension(R.dimen.avatar_chat_overview_radius) + / resources.getDimension(R.dimen.avatar_chat_overview_size); + roundedBitmapDrawable.setCornerRadius(result.getWidth() * radius); + } imageView.setImageDrawable(roundedBitmapDrawable); } diff --git a/app/src/main/java/im/conversations/android/ui/graphics/drawable/AvatarDrawable.java b/app/src/main/java/im/conversations/android/ui/graphics/drawable/AvatarDrawable.java index b51d8b32b..943ce2f5b 100644 --- a/app/src/main/java/im/conversations/android/ui/graphics/drawable/AvatarDrawable.java +++ b/app/src/main/java/im/conversations/android/ui/graphics/drawable/AvatarDrawable.java @@ -20,6 +20,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.ColorDrawable; import com.google.android.material.elevation.SurfaceColors; @@ -44,17 +45,22 @@ public class AvatarDrawable extends ColorDrawable { private final int intrinsicWidth; private final Context context; + private final boolean circular; + private final int roundedCornerRadius; public AvatarDrawable(final Context context, final AddressWithName addressWithName) { this.context = context; final String name = addressWithName.name; - final Jid key = addressWithName.address; this.paint = getPaint(addressWithName.address); this.textPaint = getTextPaint(); final Matcher matcher = LETTER_PATTERN.matcher(Strings.nullToEmpty(name)); this.letter = matcher.find() ? matcher.group().toUpperCase(Locale.ROOT) : null; + final var resources = context.getResources(); final int avatarDrawableSize = - context.getResources().getDimensionPixelSize(R.dimen.avatar_drawable_size); + resources.getDimensionPixelSize(R.dimen.avatar_chat_overview_size); + this.circular = resources.getBoolean(R.bool.avatar_chat_overview_circular); + this.roundedCornerRadius = + resources.getDimensionPixelSize(R.dimen.avatar_chat_overview_radius); this.intrinsicHeight = avatarDrawableSize; this.intrinsicWidth = avatarDrawableSize; } @@ -78,16 +84,25 @@ public class AvatarDrawable extends ColorDrawable { @Override public void draw(final Canvas canvas) { - final float midX = getBounds().width() / 2.0f; - final float midY = getBounds().height() / 2.0f; final float radius = Math.min(getBounds().width(), getBounds().height()) / 2.0f; - textPaint.setTextSize(radius); + this.textPaint.setTextSize(radius); final Rect r = new Rect(); canvas.getClipBounds(r); final int cHeight = r.height(); final int cWidth = r.width(); - // TODO if we ever want to do rounded corners we can use drawRoundRect() - canvas.drawCircle(midX, midY, radius, paint); + final var roundedSquareRadius = + context.getResources().getDimensionPixelSize(R.dimen.avatar_chat_overview_radius); + if (this.circular) { + final float midX = getBounds().width() / 2.0f; + final float midY = getBounds().height() / 2.0f; + canvas.drawCircle(midX, midY, radius, paint); + } else { + canvas.drawRoundRect( + new RectF(0, 0, getBounds().width(), getBounds().height()), + roundedSquareRadius, + roundedSquareRadius, + paint); + } if (letter == null) { return; } diff --git a/app/src/main/java/im/conversations/android/xmpp/manager/AvatarManager.java b/app/src/main/java/im/conversations/android/xmpp/manager/AvatarManager.java index 7913a33d7..2b24b1fc8 100644 --- a/app/src/main/java/im/conversations/android/xmpp/manager/AvatarManager.java +++ b/app/src/main/java/im/conversations/android/xmpp/manager/AvatarManager.java @@ -3,6 +3,7 @@ package im.conversations.android.xmpp.manager; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.media.ThumbnailUtils; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; import com.google.common.hash.Hashing; @@ -102,7 +103,12 @@ public class AvatarManager extends AbstractManager { return Futures.transform( getAvatar(address, type, id), bytes -> { - return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + final var sourceBitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + final var size = Math.min(sourceBitmap.getHeight(), sourceBitmap.getWidth()); + // return a square version of the avatar. we are not displaying the rest and can + // save the bytes plus the corner radius calculation in AvatarFetcher requires a + // square + return ThumbnailUtils.extractThumbnail(sourceBitmap, size, size); }, CPU_EXECUTOR); } diff --git a/app/src/main/res/layout/item_chatoverview.xml b/app/src/main/res/layout/item_chatoverview.xml index 68650a18f..46aea7fe5 100644 --- a/app/src/main/res/layout/item_chatoverview.xml +++ b/app/src/main/res/layout/item_chatoverview.xml @@ -10,9 +10,10 @@ diff --git a/app/src/main/res/values/avatars.xml b/app/src/main/res/values/avatars.xml new file mode 100644 index 000000000..34bdf2001 --- /dev/null +++ b/app/src/main/res/values/avatars.xml @@ -0,0 +1,5 @@ + + 40dp + false + 10dp + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 74b2bbde2..b41ec9b26 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,5 +8,4 @@ 8dp 12dp 96dp - 40dp