Fix up profile picture display.

This commit is contained in:
Mikunj 2019-11-27 08:53:57 +11:00
parent ee00241515
commit 5038dec3d1
8 changed files with 127 additions and 115 deletions

View File

@ -43,7 +43,6 @@
android:id="@+id/avatar_background"
android:layout_width="80dp"
android:layout_height="80dp"
android:visibility="gone"
android:layout_marginStart="32dp"
android:layout_marginTop="4dp"
android:src="@drawable/circle_tintable"
@ -56,7 +55,6 @@
android:id="@+id/avatar_placeholder"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_profile_default"
@ -71,7 +69,6 @@
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/avatar_background"
app:layout_constraintEnd_toEndOf="@+id/avatar_background"
app:layout_constraintStart_toStartOf="@+id/avatar_background"
@ -81,7 +78,6 @@
android:id="@+id/camera_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:visibility="gone"
android:layout_marginStart="35dp"
android:layout_marginTop="35dp"
android:cropToPadding="false"
@ -94,7 +90,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="49dp"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="4dp"
android:layout_weight="1"
@ -105,7 +101,7 @@
app:layout_constraintBottom_toTopOf="@+id/description_text"
app:layout_constraintEnd_toStartOf="@+id/emoji_toggle"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/avatar_background"
app:layout_constraintStart_toEndOf="@+id/avatar_background"
app:layout_constraintTop_toBottomOf="@+id/title" />
<org.thoughtcrime.securesms.components.emoji.EmojiToggle

View File

@ -22,6 +22,7 @@ import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Outline;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@ -38,8 +39,11 @@ import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.components.RatingManager;
import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.conversation.ConversationActivity;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.database.Address;
@ -48,6 +52,7 @@ import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo;
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
import org.thoughtcrime.securesms.loki.AddPublicChatActivity;
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.permissions.Permissions;
@ -197,45 +202,25 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
});
profilePictureImageView.setClipToOutline(true);
// Display the correct identicon if we're a secondary device
String currentUser = TextSecurePreferences.getLocalNumber(this);
String recipientAddress = recipient.getAddress().serialize();
String primaryAddress = TextSecurePreferences.getMasterHexEncodedPublicKey(this);
String profileAddress = (recipientAddress.equalsIgnoreCase(currentUser) && primaryAddress != null) ? primaryAddress : recipientAddress;
Recipient primaryRecipient = Recipient.from(this, Address.fromSerialized(profileAddress), false);
profilePictureImageView.setClipToOutline(true);
profilePictureImageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
int width = profilePictureImageView.getWidth();
int height = profilePictureImageView.getHeight();
if (width == 0 || height == 0) return true;
profilePictureImageView.getViewTreeObserver().removeOnPreDrawListener(this);
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, profileAddress.toLowerCase());
profilePictureImageView.setImageDrawable(identicon);
return true;
}
});
/*
String name = Optional.fromNullable(recipient.getName()).or(Optional.fromNullable(TextSecurePreferences.getProfileName(this))).or("");
MaterialColor fallbackColor = recipient.getColor();
if (fallbackColor == ContactColors.UNKNOWN_COLOR && !TextUtils.isEmpty(name)) {
fallbackColor = ContactColors.generateFor(name);
}
Drawable fallback = new GeneratedContactPhoto(name, R.drawable.ic_profile_default).asDrawable(this, fallbackColor.toAvatarColor(this));
Drawable fallback = primaryRecipient.getFallbackContactPhotoDrawable(this, false);
GlideApp.with(this)
.load(new ProfileContactPhoto(recipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this))))
.load(new ProfileContactPhoto(primaryRecipient.getAddress(), String.valueOf(TextSecurePreferences.getProfileAvatarId(this))))
.fallback(fallback)
.error(fallback)
.circleCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(icon);
*/
.circleCrop()
.into(profilePictureImageView);
profilePictureImageView.setOnClickListener(v -> handleDisplaySettings());
}

View File

@ -5,6 +5,7 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
@ -43,7 +44,7 @@ public final class AvatarSelection {
CropImage.activity(inputFile)
.setGuidelines(CropImageView.Guidelines.ON)
.setAspectRatio(1, 1)
.setCropShape(CropImageView.CropShape.OVAL)
.setCropShape(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? CropImageView.CropShape.RECTANGLE : CropImageView.CropShape.OVAL)
.setOutputUri(outputFile)
.setAllowRotation(true)
.setAllowFlipping(true)

View File

@ -11,22 +11,23 @@ import android.provider.ContactsContract;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.AppCompatImageView;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
import org.thoughtcrime.securesms.color.MaterialColor;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
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.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.Objects;
import network.loki.messenger.R;
@ -52,7 +53,9 @@ public class AvatarImageView extends AppCompatImageView {
private boolean inverted;
private Paint outlinePaint;
private OnClickListener listener;
private Recipient recipient;
private @Nullable RecipientContactPhoto recipientContactPhoto;
private @NonNull Drawable unknownRecipientDrawable;
public AvatarImageView(Context context) {
super(context);
@ -75,23 +78,27 @@ public class AvatarImageView extends AppCompatImageView {
outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
});
setClipToOutline(true);
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 = canvas.getWidth() / 2;
float cy = canvas.getHeight() / 2;
float radius = (canvas.getWidth() / 2) - (outlinePaint.getStrokeWidth() / 2);
float width = getWidth() - getPaddingRight() - getPaddingLeft();
float height = getHeight() - getPaddingBottom() - getPaddingTop();
float cx = width / 2f;
float cy = height / 2f;
float radius = Math.min(cx, cy) - (outlinePaint.getStrokeWidth() / 2f);
canvas.translate(getPaddingLeft(), getPaddingTop());
canvas.drawCircle(cx, cy, radius, outlinePaint);
}
@ -104,36 +111,46 @@ public class AvatarImageView extends AppCompatImageView {
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateImage(w, h);
if (recipientContactPhoto != null) { updateAvatar(recipientContactPhoto.recipient); }
}
public void update(String hexEncodedPublicKey) {
Address address = Address.fromSerialized(hexEncodedPublicKey);
if (recipient == null || !address.equals(recipient.getAddress())) {
this.recipient = Recipient.from(getContext(), address, false);
updateImage();
}
Recipient recipient = Recipient.from(getContext(), address, false);
updateAvatar(recipient);
}
private void updateAvatar(Recipient recipient) {
setAvatar(GlideApp.with(getContext()), recipient, false);
}
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
if (this.recipient == null || !this.recipient.equals(recipient)) {
this.recipient = recipient;
updateImage();
}
/*
if (recipient != null) {
requestManager.load(recipient.getContactPhoto())
.fallback(recipient.getFallbackContactPhotoDrawable(getContext(), inverted))
.error(recipient.getFallbackContactPhotoDrawable(getContext(), inverted))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.circleCrop()
.into(this);
setAvatarClickHandler(recipient, quickContactEnabled);
RecipientContactPhoto photo = new RecipientContactPhoto(recipient);
if (!photo.equals(recipientContactPhoto)) {
requestManager.clear(this);
recipientContactPhoto = photo;
Drawable fallbackContactPhotoDrawable = photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted);
if (photo.contactPhoto != null) {
requestManager.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;
requestManager.clear(this);
setImageDrawable(unknownRecipientDrawable);
super.setOnClickListener(listener);
}
*/
}
public void clear(@NonNull GlideRequests glideRequests) {
@ -154,32 +171,25 @@ public class AvatarImageView extends AppCompatImageView {
}
}
private void updateImage() { updateImage(getWidth(), getHeight()); }
private static class RecipientContactPhoto {
private void updateImage(int w, int h) {
if (w == 0 || h == 0 || recipient == null) { return; }
private final @NonNull Recipient recipient;
private final @Nullable ContactPhoto contactPhoto;
private final boolean ready;
Drawable image;
Context context = this.getContext();
if (recipient.isGroupRecipient()) {
String name = Optional.fromNullable(recipient.getName()).or(Optional.fromNullable(TextSecurePreferences.getProfileName(context))).or("");
MaterialColor fallbackColor = recipient.getColor();
if (fallbackColor == ContactColors.UNKNOWN_COLOR && !TextUtils.isEmpty(name)) {
fallbackColor = ContactColors.generateFor(name);
}
image = new GeneratedContactPhoto(name, R.drawable.ic_profile_default).asDrawable(context, fallbackColor.toAvatarColor(context));
} else {
// Default to primary device image
String ourPublicKey = TextSecurePreferences.getLocalNumber(context);
String ourPrimaryDevice = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
String recipientAddress = recipient.getAddress().serialize();
String profileAddress = (ourPrimaryDevice != null && ourPublicKey.equals(recipientAddress)) ? ourPrimaryDevice : recipientAddress;
image = new JazzIdenticonDrawable(w, h, profileAddress.toLowerCase());
RecipientContactPhoto(@NonNull Recipient recipient) {
this.recipient = recipient;
this.ready = !recipient.isResolving();
this.contactPhoto = recipient.getContactPhoto();
}
setImageDrawable(image);
}
public boolean equals(@Nullable RecipientContactPhoto other) {
if (other == null) return false;
return other.recipient.equals(recipient) &&
other.recipient.getColor().equals(recipient.getColor()) &&
other.ready == ready &&
Objects.equals(other.contactPhoto, contactPhoto);
}
}
}

View File

@ -0,0 +1,22 @@
package org.thoughtcrime.securesms.loki
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.v7.content.res.AppCompatResources
import network.loki.messenger.R
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto
class JazzIdenticonContactPhoto(val hexEncodedPublicKey: String) : FallbackContactPhoto {
override fun asDrawable(context: Context, color: Int): Drawable {
return asDrawable(context, color, false)
}
override fun asDrawable(context: Context, color: Int, inverted: Boolean): Drawable {
val targetSize = context.resources.getDimensionPixelSize(R.dimen.contact_photo_target_size)
return JazzIdenticonDrawable(targetSize, targetSize, hexEncodedPublicKey)
}
override fun asCallCard(context: Context): Drawable? {
return AppCompatResources.getDrawable(context, R.drawable.ic_person_large)
}
}

View File

@ -5,6 +5,7 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.preference.Preference;
@ -13,14 +14,17 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.database.Address;
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
import org.thoughtcrime.securesms.loki.MnemonicUtilities;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.loki.crypto.MnemonicCodec;
@ -99,28 +103,16 @@ public class ProfilePreference extends Preference {
}
});
avatarView.setClipToOutline(true);
avatarView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
int width = avatarView.getWidth();
int height = avatarView.getHeight();
if (width == 0 || height == 0) return true;
avatarView.getViewTreeObserver().removeOnPreDrawListener(this);
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, publicKey.toLowerCase());
avatarView.setImageDrawable(identicon);
return true;
}
});
/*
Drawable fallback = Recipient.from(context, localAddress, false).getFallbackContactPhotoDrawable(context, false);
GlideApp.with(getContext().getApplicationContext())
.load(new ProfileContactPhoto(localAddress, String.valueOf(TextSecurePreferences.getProfileAvatarId(getContext()))))
.error(new ResourceContactPhoto(R.drawable.ic_camera_alt_white_24dp).asDrawable(getContext(), getContext().getResources().getColor(R.color.grey_400)))
.fallback(fallback)
.error(fallback)
.circleCrop()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(avatarView);
*/
if (!TextUtils.isEmpty(profileName)) {
profileNameView.setText(profileName);

View File

@ -44,10 +44,12 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.loki.JazzIdenticonContactPhoto;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
@ -455,11 +457,15 @@ public class Recipient implements RecipientModifiedListener {
}
public synchronized @NonNull FallbackContactPhoto getFallbackContactPhoto() {
if (isLocalNumber) return new ResourceContactPhoto(R.drawable.ic_note_to_self);
if (isResolving()) return new TransparentContactPhoto();
else if (isGroupRecipient()) return new ResourceContactPhoto(R.drawable.ic_group_white_24dp, R.drawable.ic_group_large);
else if (!TextUtils.isEmpty(name)) return new GeneratedContactPhoto(name, R.drawable.ic_profile_default);
else return new ResourceContactPhoto(R.drawable.ic_profile_default, R.drawable.ic_person_large);
else if (isGroupRecipient()) return new GeneratedContactPhoto(name, R.drawable.ic_profile_default);
else {
String currentUser = TextSecurePreferences.getLocalNumber(context);
String recipientAddress = address.serialize();
String primaryAddress = TextSecurePreferences.getMasterHexEncodedPublicKey(context);
String profileAddress = (recipientAddress.equalsIgnoreCase(currentUser) && primaryAddress != null) ? primaryAddress : recipientAddress;
return new JazzIdenticonContactPhoto(profileAddress);
}
}
public synchronized @Nullable ContactPhoto getContactPhoto() {

View File

@ -11,7 +11,7 @@ import java.io.File;
public class FileProviderUtil {
private static final String AUTHORITY = "org.thoughtcrime.securesms.fileprovider";
private static final String AUTHORITY = "network.loki.securesms.fileprovider";
public static Uri getUriFor(@NonNull Context context, @NonNull File file) {
if (Build.VERSION.SDK_INT >= 24) return FileProvider.getUriForFile(context, AUTHORITY, file);