Fix emoji avatar missing after edit.
This commit is contained in:
parent
5e968eb831
commit
18ba5fa291
15 changed files with 181 additions and 69 deletions
|
@ -48,8 +48,9 @@ object AvatarRenderer {
|
|||
avatar: Avatar.Text,
|
||||
inverted: Boolean = false,
|
||||
size: Int = DIMENSIONS,
|
||||
synchronous: Boolean = false
|
||||
): Drawable {
|
||||
return TextAvatarDrawable(context, avatar, inverted, size)
|
||||
return TextAvatarDrawable(context, avatar, inverted, size, synchronous)
|
||||
}
|
||||
|
||||
private fun renderVector(context: Context, avatar: Avatar.Vector, onAvatarRendered: (Media) -> Unit, onRenderFailed: (Throwable?) -> Unit) {
|
||||
|
@ -66,7 +67,7 @@ object AvatarRenderer {
|
|||
|
||||
private fun renderText(context: Context, avatar: Avatar.Text, onAvatarRendered: (Media) -> Unit, onRenderFailed: (Throwable?) -> Unit) {
|
||||
renderInBackground(context, onAvatarRendered, onRenderFailed) { canvas ->
|
||||
val textDrawable = createTextDrawable(context, avatar)
|
||||
val textDrawable = createTextDrawable(context, avatar, synchronous = true)
|
||||
|
||||
canvas.drawColor(avatar.color.backgroundColor)
|
||||
textDrawable.draw(canvas)
|
||||
|
|
|
@ -3,52 +3,59 @@ package org.thoughtcrime.securesms.avatar
|
|||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.TypedValue
|
||||
import android.view.Gravity
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
import android.text.Layout
|
||||
import android.text.SpannableString
|
||||
import android.text.StaticLayout
|
||||
import android.text.TextPaint
|
||||
import androidx.core.graphics.withTranslation
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider
|
||||
|
||||
/**
|
||||
* Uses EmojiTextView to properly render a Text Avatar with emoji in it.
|
||||
*/
|
||||
class TextAvatarDrawable(
|
||||
context: Context,
|
||||
avatar: Avatar.Text,
|
||||
private val context: Context,
|
||||
private val avatar: Avatar.Text,
|
||||
inverted: Boolean = false,
|
||||
private val size: Int = AvatarRenderer.DIMENSIONS,
|
||||
private val synchronous: Boolean = false
|
||||
) : Drawable() {
|
||||
|
||||
private val layout: FrameLayout = FrameLayout(context)
|
||||
private val textView: EmojiTextView = EmojiTextView(context)
|
||||
|
||||
private val textPaint = TextPaint(Paint.ANTI_ALIAS_FLAG)
|
||||
init {
|
||||
textView.typeface = AvatarRenderer.getTypeface(context)
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, Avatars.getTextSizeForLength(context, avatar.text, size * 0.8f, size * 0.45f))
|
||||
textView.text = avatar.text
|
||||
textView.gravity = Gravity.CENTER
|
||||
textView.setTextColor(if (inverted) avatar.color.backgroundColor else avatar.color.foregroundColor)
|
||||
textView.setForceCustomEmoji(true)
|
||||
textPaint.typeface = AvatarRenderer.getTypeface(context)
|
||||
textPaint.color = if (inverted) avatar.color.backgroundColor else avatar.color.foregroundColor
|
||||
textPaint.density = context.resources.displayMetrics.density
|
||||
|
||||
layout.addView(textView)
|
||||
|
||||
textView.updateLayoutParams {
|
||||
width = size
|
||||
height = size
|
||||
}
|
||||
|
||||
layout.measure(size, size)
|
||||
layout.layout(0, 0, size, size)
|
||||
setBounds(0, 0, size, size)
|
||||
}
|
||||
|
||||
override fun getIntrinsicHeight(): Int = size
|
||||
|
||||
override fun getIntrinsicWidth(): Int = size
|
||||
|
||||
override fun draw(canvas: Canvas) {
|
||||
layout.draw(canvas)
|
||||
val textSize = Avatars.getTextSizeForLength(context, avatar.text, size * 0.8f, size * 0.45f)
|
||||
val width = bounds.width()
|
||||
val candidates = EmojiProvider.getCandidates(avatar.text)
|
||||
var hasEmoji = false
|
||||
|
||||
textPaint.textSize = textSize
|
||||
|
||||
val newText = if (candidates == null || candidates.size() == 0) {
|
||||
SpannableString(avatar.text)
|
||||
} else {
|
||||
EmojiProvider.emojify(context, candidates, avatar.text, textPaint, synchronous)
|
||||
}
|
||||
|
||||
if (newText == null) return
|
||||
|
||||
val layout = StaticLayout(SpannableString(newText), textPaint, width, Layout.Alignment.ALIGN_NORMAL, 0f, 0f, true)
|
||||
layout.draw(canvas, getStartX(layout), ((bounds.height() / 2) - ((layout.height / 2))).toFloat())
|
||||
}
|
||||
|
||||
private fun getStartX(layout: StaticLayout): Float {
|
||||
val direction = layout.getParagraphDirection(0)
|
||||
val lineWidth = layout.getLineWidth(0)
|
||||
val width = bounds.width()
|
||||
val xPos = (width - lineWidth) / 2
|
||||
return if (direction == Layout.DIR_LEFT_TO_RIGHT) xPos else -xPos
|
||||
}
|
||||
|
||||
override fun setAlpha(alpha: Int) = Unit
|
||||
|
@ -56,4 +63,10 @@ class TextAvatarDrawable(
|
|||
override fun setColorFilter(colorFilter: ColorFilter?) = Unit
|
||||
|
||||
override fun getOpacity(): Int = PixelFormat.OPAQUE
|
||||
|
||||
private fun Layout.draw(canvas: Canvas, x: Float, y: Float) {
|
||||
canvas.withTranslation(x, y) {
|
||||
draw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.util.AvatarUtil;
|
|||
import org.thoughtcrime.securesms.util.BlurTransformation;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -207,8 +208,8 @@ public final class AvatarImageView extends AppCompatImageView {
|
|||
this.chatColors = chatColors;
|
||||
recipientContactPhoto = photo;
|
||||
|
||||
Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL ? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider)
|
||||
: photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider);
|
||||
Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL ? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider, ViewUtil.getWidth(this))
|
||||
: photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider, ViewUtil.getWidth(this));
|
||||
|
||||
if (fixedSizeTarget != null) {
|
||||
requestManager.clear(fixedSizeTarget);
|
||||
|
|
|
@ -26,13 +26,15 @@ import org.thoughtcrime.securesms.util.FutureTaskListener;
|
|||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
class EmojiProvider {
|
||||
public class EmojiProvider {
|
||||
|
||||
private static final String TAG = Log.tag(EmojiProvider.class);
|
||||
private static final Paint PAINT = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
static @Nullable EmojiParser.CandidateList getCandidates(@Nullable CharSequence text) {
|
||||
public static @Nullable EmojiParser.CandidateList getCandidates(@Nullable CharSequence text) {
|
||||
if (text == null) return null;
|
||||
return new EmojiParser(EmojiSource.getLatest().getEmojiTree()).findCandidates(text);
|
||||
}
|
||||
|
@ -64,6 +66,32 @@ class EmojiProvider {
|
|||
return builder;
|
||||
}
|
||||
|
||||
public static @Nullable Spannable emojify(@NonNull Context context,
|
||||
@Nullable EmojiParser.CandidateList matches,
|
||||
@Nullable CharSequence text,
|
||||
@NonNull Paint paint,
|
||||
boolean synchronous)
|
||||
{
|
||||
if (matches == null || text == null) return null;
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(text);
|
||||
|
||||
for (EmojiParser.Candidate candidate : matches) {
|
||||
Drawable drawable;
|
||||
if (synchronous) {
|
||||
drawable = getEmojiDrawableSync(context, candidate.getDrawInfo());
|
||||
} else {
|
||||
drawable = getEmojiDrawable(context, candidate.getDrawInfo(), null);
|
||||
}
|
||||
|
||||
if (drawable != null) {
|
||||
builder.setSpan(new EmojiSpan(context, drawable, paint), candidate.getStartIndex(), candidate.getEndIndex(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static @Nullable Drawable getEmojiDrawable(@NonNull Context context, @Nullable CharSequence emoji) {
|
||||
EmojiDrawInfo drawInfo = EmojiSource.getLatest().getEmojiTree().getEmoji(emoji, 0, emoji.length());
|
||||
return getEmojiDrawable(context, drawInfo, null);
|
||||
|
@ -113,6 +141,43 @@ class EmojiProvider {
|
|||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an EmojiDrawable from the Page Cache synchronously
|
||||
*
|
||||
* @param context Context object used in reading and writing from disk
|
||||
* @param drawInfo Information about the emoji being displayed
|
||||
*/
|
||||
private static @Nullable Drawable getEmojiDrawableSync(@NonNull Context context, @Nullable EmojiDrawInfo drawInfo) {
|
||||
ThreadUtil.assertNotMainThread();
|
||||
if (drawInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1;
|
||||
final EmojiSource source = EmojiSource.getLatest();
|
||||
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale);
|
||||
|
||||
EmojiPageCache.LoadResult loadResult = EmojiPageCache.INSTANCE.load(context, drawInfo.getPage(), lowMemoryDecodeScale);
|
||||
Bitmap bitmap = null;
|
||||
|
||||
if (loadResult instanceof EmojiPageCache.LoadResult.Immediate) {
|
||||
Log.d(TAG, "Cached emoji page: " + drawInfo.getPage().getUri().toString());
|
||||
bitmap = ((EmojiPageCache.LoadResult.Immediate) loadResult).getBitmap();
|
||||
} else if (loadResult instanceof EmojiPageCache.LoadResult.Async) {
|
||||
Log.d(TAG, "Loading emoji page: " + drawInfo.getPage().getUri().toString());
|
||||
try {
|
||||
bitmap = ((EmojiPageCache.LoadResult.Async) loadResult).getTask().get(2, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException exception) {
|
||||
Log.d(TAG, "Failed to load emoji bitmap resource", exception);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Unexpected subclass " + loadResult.getClass());
|
||||
}
|
||||
|
||||
drawable.setBitmap(bitmap);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
static final class EmojiDrawable extends Drawable {
|
||||
private final float intrinsicWidth;
|
||||
private final float intrinsicHeight;
|
||||
|
@ -160,7 +225,6 @@ class EmojiProvider {
|
|||
}
|
||||
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
ThreadUtil.assertMainThread();
|
||||
if (bmp == null || !bmp.sameAs(bitmap)) {
|
||||
bmp = bitmap;
|
||||
invalidateSelf();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.thoughtcrime.securesms.components.emoji;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.FontMetricsInt;
|
||||
|
@ -25,6 +26,15 @@ public class EmojiSpan extends AnimatingImageSpan {
|
|||
getDrawable().setBounds(0, 0, size, size);
|
||||
}
|
||||
|
||||
public EmojiSpan(@NonNull Context context, @NonNull Drawable drawable, @NonNull Paint paint) {
|
||||
super(drawable, null);
|
||||
fontMetrics = paint.getFontMetricsInt();
|
||||
size = fontMetrics != null ? Math.abs(fontMetrics.descent) + Math.abs(fontMetrics.ascent)
|
||||
: context.getResources().getDimensionPixelSize(R.dimen.conversation_item_body_text_size);
|
||||
|
||||
getDrawable().setBounds(0, 0, size, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
|
||||
if (fm != null && this.fontMetrics != null) {
|
||||
|
@ -48,6 +58,7 @@ public class EmojiSpan extends AnimatingImageSpan {
|
|||
int height = bottom - top;
|
||||
int centeringMargin = (height - size) / 2;
|
||||
int adjustedMargin = (int) (centeringMargin * SHIFT_FACTOR);
|
||||
int adjustedBottom = bottom - adjustedMargin;
|
||||
super.draw(canvas, text, start, end, x, top, y, bottom - adjustedMargin, paint);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ open class SimpleEmojiTextView @JvmOverloads constructor(
|
|||
} else {
|
||||
EmojiProvider.emojify(newCandidates, newContent, this)
|
||||
}
|
||||
bufferType = BufferType.SPANNABLE
|
||||
super.setText(newText, type)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class GeneratedContactPhoto implements FallbackContactPhoto {
|
|||
|
||||
@Override
|
||||
public Drawable asDrawable(@NonNull Context context, @NonNull AvatarColor color, boolean inverted) {
|
||||
int targetSize = this.targetSize != -1
|
||||
int targetSize = this.targetSize > 0
|
||||
? this.targetSize
|
||||
: context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class GeneratedContactPhoto implements FallbackContactPhoto {
|
|||
if (!TextUtils.isEmpty(character)) {
|
||||
Avatars.ForegroundColor foregroundColor = Avatars.getForegroundColor(color);
|
||||
Avatar.Text avatar = new Avatar.Text(character, new Avatars.ColorPair(color, foregroundColor), Avatar.DatabaseId.DoNotPersist.INSTANCE);
|
||||
Drawable foreground = AvatarRenderer.createTextDrawable(context, avatar, inverted, targetSize);
|
||||
Drawable foreground = AvatarRenderer.createTextDrawable(context, avatar, inverted, targetSize, false);
|
||||
Drawable background = Objects.requireNonNull(ContextCompat.getDrawable(context, R.drawable.circle_tintable));
|
||||
|
||||
background.setColorFilter(new SimpleColorFilter(inverted ? foregroundColor.getColorInt() : color.colorInt()));
|
||||
|
|
|
@ -490,7 +490,7 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
private void initializeProfileIcon(@NonNull Recipient recipient) {
|
||||
ImageView icon = requireView().findViewById(R.id.toolbar_icon);
|
||||
|
||||
AvatarUtil.loadIconIntoImageView(recipient, icon);
|
||||
AvatarUtil.loadIconIntoImageView(recipient, icon, getResources().getDimensionPixelSize(R.dimen.toolbar_avatar_size));
|
||||
icon.setOnClickListener(v -> getNavigator().goToAppSettings());
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ public class ReviewBannerView extends LinearLayout {
|
|||
|
||||
@NonNull
|
||||
@Override
|
||||
public FallbackContactPhoto getPhotoForRecipientWithName(String name) {
|
||||
public FallbackContactPhoto getPhotoForRecipientWithName(String name, int targetSize) {
|
||||
return new FixedSizeGeneratedContactPhoto(name, R.drawable.ic_profile_outline_20);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|||
import org.thoughtcrime.securesms.phonenumbers.NumberUtil;
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;
|
||||
import org.thoughtcrime.securesms.profiles.ProfileName;
|
||||
import org.thoughtcrime.securesms.util.AvatarUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.StringUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
@ -791,19 +792,23 @@ public class Recipient {
|
|||
}
|
||||
|
||||
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted) {
|
||||
return getFallbackContactPhotoDrawable(context, inverted, DEFAULT_FALLBACK_PHOTO_PROVIDER);
|
||||
return getFallbackContactPhotoDrawable(context, inverted, DEFAULT_FALLBACK_PHOTO_PROVIDER, AvatarUtil.UNDEFINED_SIZE);
|
||||
}
|
||||
|
||||
public @NonNull Drawable getSmallFallbackContactPhotoDrawable(Context context, boolean inverted) {
|
||||
return getSmallFallbackContactPhotoDrawable(context, inverted, DEFAULT_FALLBACK_PHOTO_PROVIDER);
|
||||
}
|
||||
|
||||
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
|
||||
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asDrawable(context, avatarColor, inverted);
|
||||
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider, int targetSize) {
|
||||
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER), targetSize).asDrawable(context, avatarColor, inverted);
|
||||
}
|
||||
|
||||
public @NonNull Drawable getSmallFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
|
||||
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asSmallDrawable(context, avatarColor, inverted);
|
||||
return getSmallFallbackContactPhotoDrawable(context, inverted, fallbackPhotoProvider, AvatarUtil.UNDEFINED_SIZE);
|
||||
}
|
||||
|
||||
public @NonNull Drawable getSmallFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider, int targetSize) {
|
||||
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER), targetSize).asSmallDrawable(context, avatarColor, inverted);
|
||||
}
|
||||
|
||||
public @NonNull FallbackContactPhoto getFallbackContactPhoto() {
|
||||
|
@ -811,13 +816,17 @@ public class Recipient {
|
|||
}
|
||||
|
||||
public @NonNull FallbackContactPhoto getFallbackContactPhoto(@NonNull FallbackPhotoProvider fallbackPhotoProvider) {
|
||||
return getFallbackContactPhoto(fallbackPhotoProvider, AvatarUtil.UNDEFINED_SIZE);
|
||||
}
|
||||
|
||||
public @NonNull FallbackContactPhoto getFallbackContactPhoto(@NonNull FallbackPhotoProvider fallbackPhotoProvider, int targetSize) {
|
||||
if (isSelf) return fallbackPhotoProvider.getPhotoForLocalNumber();
|
||||
else if (isResolving()) return fallbackPhotoProvider.getPhotoForResolvingRecipient();
|
||||
else if (isGroupInternal()) return fallbackPhotoProvider.getPhotoForGroup();
|
||||
else if (isGroup()) return fallbackPhotoProvider.getPhotoForGroup();
|
||||
else if (!TextUtils.isEmpty(groupName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(groupName);
|
||||
else if (!TextUtils.isEmpty(systemContactName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(systemContactName);
|
||||
else if (!signalProfileName.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(signalProfileName.toString());
|
||||
else if (!TextUtils.isEmpty(groupName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(groupName, targetSize);
|
||||
else if (!TextUtils.isEmpty(systemContactName)) return fallbackPhotoProvider.getPhotoForRecipientWithName(systemContactName, targetSize);
|
||||
else if (!signalProfileName.isEmpty()) return fallbackPhotoProvider.getPhotoForRecipientWithName(signalProfileName.toString(), targetSize);
|
||||
else return fallbackPhotoProvider.getPhotoForRecipientWithoutName();
|
||||
}
|
||||
|
||||
|
@ -1224,8 +1233,8 @@ public class Recipient {
|
|||
return new ResourceContactPhoto(R.drawable.ic_group_outline_34, R.drawable.ic_group_outline_20, R.drawable.ic_group_outline_48);
|
||||
}
|
||||
|
||||
public @NonNull FallbackContactPhoto getPhotoForRecipientWithName(String name) {
|
||||
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40);
|
||||
public @NonNull FallbackContactPhoto getPhotoForRecipientWithName(String name, int targetSize) {
|
||||
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40, targetSize);
|
||||
}
|
||||
|
||||
public @NonNull FallbackContactPhoto getPhotoForRecipientWithoutName() {
|
||||
|
|
|
@ -30,6 +30,8 @@ import java.util.concurrent.ExecutionException;
|
|||
|
||||
public final class AvatarUtil {
|
||||
|
||||
public static final int UNDEFINED_SIZE = -1;
|
||||
|
||||
private AvatarUtil() {
|
||||
}
|
||||
|
||||
|
@ -71,9 +73,13 @@ public final class AvatarUtil {
|
|||
}
|
||||
|
||||
public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target) {
|
||||
loadIconIntoImageView(recipient, target, -1);
|
||||
}
|
||||
|
||||
public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target, int requestedSize) {
|
||||
Context context = target.getContext();
|
||||
|
||||
requestCircle(GlideApp.with(context).asDrawable(), context, recipient).into(target);
|
||||
requestCircle(GlideApp.with(context).asDrawable(), context, recipient, requestedSize).into(target);
|
||||
}
|
||||
|
||||
public static Bitmap loadIconBitmapSquareNoCache(@NonNull Context context,
|
||||
|
@ -92,7 +98,7 @@ public final class AvatarUtil {
|
|||
@WorkerThread
|
||||
public static IconCompat getIconForNotification(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
try {
|
||||
return IconCompat.createWithBitmap(requestCircle(GlideApp.with(context).asBitmap(), context, recipient).submit().get());
|
||||
return IconCompat.createWithBitmap(requestCircle(GlideApp.with(context).asBitmap(), context, recipient, UNDEFINED_SIZE).submit().get());
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
|
@ -114,25 +120,25 @@ public final class AvatarUtil {
|
|||
@WorkerThread
|
||||
public static Bitmap getBitmapForNotification(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
try {
|
||||
return requestCircle(GlideApp.with(context).asBitmap(), context, recipient).submit().get();
|
||||
return requestCircle(GlideApp.with(context).asBitmap(), context, recipient, UNDEFINED_SIZE).submit().get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> GlideRequest<T> requestCircle(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient) {
|
||||
return request(glideRequest, context, recipient).circleCrop();
|
||||
private static <T> GlideRequest<T> requestCircle(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, int targetSize) {
|
||||
return request(glideRequest, context, recipient, targetSize).circleCrop();
|
||||
}
|
||||
|
||||
private static <T> GlideRequest<T> requestSquare(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient) {
|
||||
return request(glideRequest, context, recipient).centerCrop();
|
||||
return request(glideRequest, context, recipient, UNDEFINED_SIZE).centerCrop();
|
||||
}
|
||||
|
||||
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient) {
|
||||
return request(glideRequest, context, recipient, true);
|
||||
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, int targetSize) {
|
||||
return request(glideRequest, context, recipient, true, targetSize);
|
||||
}
|
||||
|
||||
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf) {
|
||||
private static <T> GlideRequest<T> request(@NonNull GlideRequest<T> glideRequest, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf, int targetSize) {
|
||||
final ContactPhoto photo;
|
||||
if (Recipient.self().equals(recipient) && loadSelf) {
|
||||
photo = new ProfileContactPhoto(recipient, recipient.getProfileAvatar());
|
||||
|
@ -141,7 +147,7 @@ public final class AvatarUtil {
|
|||
}
|
||||
|
||||
final GlideRequest<T> request = glideRequest.load(photo)
|
||||
.error(getFallback(context, recipient))
|
||||
.error(getFallback(context, recipient, targetSize))
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL);
|
||||
|
||||
if (recipient.shouldBlurAvatar()) {
|
||||
|
@ -151,9 +157,9 @@ public final class AvatarUtil {
|
|||
}
|
||||
}
|
||||
|
||||
private static Drawable getFallback(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
private static Drawable getFallback(@NonNull Context context, @NonNull Recipient recipient, int targetSize) {
|
||||
String name = Optional.fromNullable(recipient.getDisplayName(context)).or("");
|
||||
|
||||
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40).asDrawable(context, recipient.getAvatarColor());
|
||||
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40, targetSize).asDrawable(context, recipient.getAvatarColor());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -280,6 +280,10 @@ public final class ViewUtil {
|
|||
view.requestLayout();
|
||||
}
|
||||
|
||||
public static int getWidth(@NonNull View view) {
|
||||
return view.getLayoutParams().width;
|
||||
}
|
||||
|
||||
public static void setPaddingTop(@NonNull View view, int padding) {
|
||||
view.setPadding(view.getPaddingLeft(), padding, view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/toolbar_icon"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_width="@dimen/toolbar_avatar_size"
|
||||
android:layout_height="@dimen/toolbar_avatar_size"
|
||||
android:layout_alignParentStart="true"
|
||||
android:contentDescription="@string/conversation_list_settings_shortcut"
|
||||
android:layout_marginStart="@dimen/toolbar_avatar_margin"
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/conversation_list_item_avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_width="@dimen/conversation_list_avatar_size"
|
||||
android:layout_height="@dimen/conversation_list_avatar_size"
|
||||
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"
|
||||
android:foreground="@drawable/contact_photo_background"
|
||||
android:layout_marginTop="12dp"
|
||||
|
|
|
@ -202,7 +202,9 @@
|
|||
|
||||
<dimen name="avatar_picker_image_width">100dp</dimen>
|
||||
|
||||
<dimen name="toolbar_avatar_size">28dp</dimen>
|
||||
<dimen name="toolbar_avatar_margin">26dp</dimen>
|
||||
<dimen name="conversation_list_avatar_size">48dp</dimen>
|
||||
|
||||
<dimen name="verify_identity_vertical_margin">16dp</dimen>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Reference in a new issue