diff --git a/src/org/thoughtcrime/securesms/ConversationListItem.java b/src/org/thoughtcrime/securesms/ConversationListItem.java index fd69ac0726..b6d393bbc4 100644 --- a/src/org/thoughtcrime/securesms/ConversationListItem.java +++ b/src/org/thoughtcrime/securesms/ConversationListItem.java @@ -22,14 +22,15 @@ import android.graphics.Typeface; import android.graphics.drawable.RippleDrawable; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import android.text.style.StyleSpan; import android.util.AttributeSet; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.thoughtcrime.securesms.components.AlertView; import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.components.DeliveryStatusView; @@ -240,7 +241,11 @@ public class ConversationListItem extends RelativeLayout @Override public void unbind() { - if (this.recipient != null) this.recipient.removeListener(this); + if (this.recipient != null) { + this.recipient.removeListener(this); + this.recipient = null; + contactPhotoImage.setAvatar(glideRequests, null, true); + } } private void setBatchState(boolean batch) { @@ -336,9 +341,11 @@ public class ConversationListItem extends RelativeLayout @Override public void onModified(final Recipient recipient) { Util.runOnMain(() -> { - fromView.setText(recipient, unreadCount == 0); - contactPhotoImage.setAvatar(glideRequests, recipient, true); - setRippleColor(recipient); + if (this.recipient == recipient) { + fromView.setText(recipient, unreadCount == 0); + contactPhotoImage.setAvatar(glideRequests, recipient, true); + setRippleColor(recipient); + } }); } diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index f12165648a..d91d828b67 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -5,22 +5,29 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.drawable.Drawable; import android.provider.ContactsContract; +import android.util.AttributeSet; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; -import android.util.AttributeSet; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; +import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto; +import org.thoughtcrime.securesms.mms.GlideApp; import org.thoughtcrime.securesms.mms.GlideRequests; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientExporter; import org.thoughtcrime.securesms.util.ThemeUtil; +import java.util.Objects; + public class AvatarImageView extends AppCompatImageView { private static final String TAG = AvatarImageView.class.getSimpleName(); @@ -44,6 +51,9 @@ public class AvatarImageView extends AppCompatImageView { private Paint outlinePaint; private OnClickListener listener; + private @Nullable RecipientContactPhoto recipientContactPhoto; + private @NonNull Drawable unknownRecipientDrawable; + public AvatarImageView(Context context) { super(context); initialize(context, null); @@ -64,16 +74,18 @@ public class AvatarImageView extends AppCompatImageView { } outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT; + + unknownRecipientDrawable = new ResourceContactPhoto(R.drawable.ic_profile_default).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted); } @Override - protected void dispatchDraw(Canvas canvas) { - super.dispatchDraw(canvas); + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + float cx = getWidth() / 2f; + float cy = getHeight() / 2f; + float radius = cx - (outlinePaint.getStrokeWidth() / 2f); - float cx = canvas.getWidth() / 2; - float cy = canvas.getHeight() / 2; - float radius = (canvas.getWidth() / 2) - (outlinePaint.getStrokeWidth() / 2); - canvas.drawCircle(cx, cy, radius, outlinePaint); } @@ -85,23 +97,34 @@ public class AvatarImageView extends AppCompatImageView { public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) { if (recipient != null) { - requestManager.load(recipient.getContactPhoto()) - .fallback(recipient.getFallbackContactPhotoDrawable(getContext(), inverted)) - .error(recipient.getFallbackContactPhotoDrawable(getContext(), inverted)) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .circleCrop() - .into(this); + RecipientContactPhoto photo = new RecipientContactPhoto(recipient); + + if (!photo.equals(recipientContactPhoto)) { + recipientContactPhoto = photo; + + Drawable fallbackContactPhotoDrawable = photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted); + + if (photo.contactPhoto != null) { + GlideApp.with(this) + .load(photo.contactPhoto) + .fallback(fallbackContactPhotoDrawable) + .error(fallbackContactPhotoDrawable) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .circleCrop() + .into(this); + } else { + setImageDrawable(fallbackContactPhotoDrawable); + } + } + setAvatarClickHandler(recipient, quickContactEnabled); } else { - setImageDrawable(new ResourceContactPhoto(R.drawable.ic_profile_default).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted)); + recipientContactPhoto = null; + setImageDrawable(unknownRecipientDrawable); super.setOnClickListener(listener); } } - public void clear(@NonNull GlideRequests glideRequests) { - glideRequests.clear(this); - } - private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) { if (!recipient.isGroupRecipient() && quickContactEnabled) { super.setOnClickListener(v -> { @@ -116,4 +139,24 @@ public class AvatarImageView extends AppCompatImageView { } } + private static class RecipientContactPhoto { + + private final @NonNull Recipient recipient; + private final @Nullable ContactPhoto contactPhoto; + private final boolean ready; + + RecipientContactPhoto(@NonNull Recipient recipient) { + this.recipient = recipient; + this.ready = !recipient.isResolving(); + this.contactPhoto = recipient.getContactPhoto(); + } + + public boolean equals(@Nullable RecipientContactPhoto other) { + if (other == null) return false; + + return other.recipient.equals(recipient) && + other.ready == ready && + Objects.equals(other.contactPhoto, contactPhoto); + } + } } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index e9dc9e729c..64d0c1a497 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -94,8 +94,6 @@ public class ContactSelectionListItem extends LinearLayout implements RecipientM recipient.removeListener(this); recipient = null; } - - contactPhotoImage.clear(glideRequests); } private void setText(int type, String name, String number, String label) {