mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Display a generated avatar icon rather than a single default.
If the contact doesn't have an image, render a color-coded background and the first letter of the contact's name. 1) Don't display anything during recipient resolution. 2) Display a # icon in material gray for recipients with no name. 3) Display a material group icon in material gray for groups with no avatar icon set. Closes #3104 // FREEBIE
This commit is contained in:
parent
356d9949b7
commit
41cad291f9
@ -5,6 +5,8 @@
|
||||
android:versionCode="113"
|
||||
android:versionName="2.13.0">
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.amulyakhare.textdrawable"/>
|
||||
|
||||
<permission android:name="org.thoughtcrime.securesms.ACCESS_SECRETS"
|
||||
android:label="Access to TextSecure Secrets"
|
||||
android:protectionLevel="signature" />
|
||||
|
@ -26,6 +26,9 @@ repositories {
|
||||
maven {
|
||||
url "https://raw.github.com/whispersystems/maven/master/shortcutbadger/releases/"
|
||||
}
|
||||
maven { // textdrawable
|
||||
url 'https://dl.bintray.com/amulyakhare/maven'
|
||||
}
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
}
|
||||
@ -64,6 +67,7 @@ dependencies {
|
||||
compile 'org.whispersystems:jobmanager:0.11.0'
|
||||
compile 'org.whispersystems:libpastelog:1.0.6'
|
||||
compile 'org.whispersystems:textsecure-android:1.3.0'
|
||||
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker:1.2'
|
||||
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
|
||||
@ -104,6 +108,7 @@ dependencyVerification {
|
||||
'org.whispersystems:jobmanager:ea9cb943c4892fb90c1eea1be30efeb85cefca213d52c788419553b58d0ed70d',
|
||||
'org.whispersystems:libpastelog:550d33c565380d90f4c671e7b8ed5f3a6da55a9fda468373177106b2eb5220b2',
|
||||
'org.whispersystems:textsecure-android:df4c1ac9ee8f7cd43c8c07d64b16e31875e04632afc3fe73f2a47292a86c79a1',
|
||||
'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
|
||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
||||
|
@ -26,17 +26,15 @@
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginRight="0dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.ForegroundImageView
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/contact_photo"
|
||||
android:foreground="@drawable/contact_photo_background"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
app:riv_oval="true"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:cropToPadding="true"
|
||||
android:contentDescription="@string/conversation_item_received__contact_photo_description"
|
||||
android:scaleType="centerCrop" />
|
||||
android:contentDescription="@string/conversation_item_received__contact_photo_description" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.IncomingBubbleContainer
|
||||
android:id="@+id/bubble"
|
||||
|
@ -17,14 +17,12 @@
|
||||
android:paddingRight="10dp"
|
||||
android:visibility="visible">
|
||||
|
||||
<com.makeramen.RoundedImageView
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/contact_photo_image"
|
||||
android:foreground="@drawable/contact_photo_background"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
app:riv_oval="true"
|
||||
android:cropToPadding="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:visibility="gone"
|
||||
tools:src="@drawable/ic_contact_picture"
|
||||
android:contentDescription="@string/conversation_list_item_view__contact_photo_image"
|
||||
@ -49,7 +47,8 @@
|
||||
android:weightSum="1"
|
||||
android:gravity="bottom">
|
||||
|
||||
<TextView android:id="@+id/from"
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/from"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -9,10 +9,9 @@
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
|
||||
<com.makeramen.RoundedImageView
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/contact_photo_image"
|
||||
android:foreground="@drawable/contact_photo_background"
|
||||
app:riv_oval="true"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_centerVertical="true"
|
||||
@ -21,7 +20,6 @@
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:cropToPadding="true"
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@drawable/ic_contact_picture"
|
||||
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
|
||||
|
||||
@ -38,7 +36,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/from"
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/from"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
|
@ -1,12 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:paddingRight="25dip">
|
||||
|
||||
<com.makeramen.RoundedImageView
|
||||
<ImageView
|
||||
android:id="@+id/contact_photo_image"
|
||||
android:layout_width="@dimen/contact_selection_photo_size"
|
||||
android:layout_height="@dimen/contact_selection_photo_size"
|
||||
@ -15,7 +14,6 @@
|
||||
android:layout_marginLeft="10dp"
|
||||
android:cropToPadding="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:riv_oval="true"
|
||||
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
|
||||
|
||||
<TextView android:id="@+id/number"
|
||||
|
@ -5,7 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.makeramen.RoundedImageView
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/contact_photo_image"
|
||||
android:foreground="@drawable/contact_photo_background"
|
||||
android:layout_width="50dp"
|
||||
@ -17,8 +17,6 @@
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:cropToPadding="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:riv_oval="true"
|
||||
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
|
||||
|
||||
<LinearLayout
|
||||
@ -32,7 +30,8 @@
|
||||
android:layout_toRightOf="@id/contact_photo_image"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/from"
|
||||
<org.thoughtcrime.securesms.components.FromTextView
|
||||
android:id="@+id/from"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
|
@ -113,4 +113,5 @@
|
||||
</declare-styleable>
|
||||
|
||||
<attr name="group_members_dialog_icon" format="reference"/>
|
||||
|
||||
</resources>
|
||||
|
@ -21,9 +21,6 @@ import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.QuickContact;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
@ -38,9 +35,9 @@ import android.widget.Toast;
|
||||
import com.afollestad.materialdialogs.AlertDialogWrapper;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationFragment.SelectionClickListener;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.BubbleContainer;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@ -85,7 +82,7 @@ public class ConversationItem extends LinearLayout {
|
||||
private TextView groupStatusText;
|
||||
private ImageView secureImage;
|
||||
private ImageView failedImage;
|
||||
private ImageView contactPhoto;
|
||||
private AvatarImageView contactPhoto;
|
||||
private ImageView deliveryImage;
|
||||
private ImageView pendingIndicator;
|
||||
private BubbleContainer bubbleContainer;
|
||||
@ -123,7 +120,7 @@ public class ConversationItem extends LinearLayout {
|
||||
this.failedImage = (ImageView)findViewById(R.id.sms_failed_indicator);
|
||||
this.mmsDownloadButton = (Button) findViewById(R.id.mms_download_button);
|
||||
this.mmsDownloadingLabel = (TextView) findViewById(R.id.mms_label_downloading);
|
||||
this.contactPhoto = (ImageView)findViewById(R.id.contact_photo);
|
||||
this.contactPhoto = (AvatarImageView) findViewById(R.id.contact_photo);
|
||||
this.deliveryImage = (ImageView)findViewById(R.id.delivered_indicator);
|
||||
this.bodyBubble = findViewById(R.id.body_bubble);
|
||||
this.pendingIndicator = (ImageView)findViewById(R.id.pending_approval_indicator);
|
||||
@ -369,30 +366,7 @@ public class ConversationItem extends LinearLayout {
|
||||
private void setContactPhotoForRecipient(final Recipient recipient) {
|
||||
if (contactPhoto == null) return;
|
||||
|
||||
Bitmap contactPhotoBitmap;
|
||||
|
||||
if ((recipient.getContactPhoto() == ContactPhotoFactory.getDefaultContactPhoto(context)) && (groupThread)) {
|
||||
contactPhotoBitmap = recipient.getGeneratedAvatar(context);
|
||||
} else {
|
||||
contactPhotoBitmap = recipient.getContactPhoto();
|
||||
}
|
||||
|
||||
contactPhoto.setImageBitmap(contactPhotoBitmap);
|
||||
|
||||
contactPhoto.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (recipient.getContactUri() != null) {
|
||||
QuickContact.showQuickContact(context, contactPhoto, recipient.getContactUri(), QuickContact.MODE_LARGE, null);
|
||||
} else {
|
||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
|
||||
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contactPhoto.setAvatar(recipient, true);
|
||||
contactPhoto.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
|
@ -22,16 +22,16 @@ import android.graphics.Typeface;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.Emoji;
|
||||
import org.thoughtcrime.securesms.util.RecipientViewUtil;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
@ -53,15 +53,15 @@ public class ConversationListItem extends RelativeLayout
|
||||
private final static Typeface BOLD_TYPEFACE = Typeface.create("sans-serif", Typeface.BOLD);
|
||||
private final static Typeface LIGHT_TYPEFACE = Typeface.create("sans-serif-light", Typeface.NORMAL);
|
||||
|
||||
private Context context;
|
||||
private Set<Long> selectedThreads;
|
||||
private Recipients recipients;
|
||||
private long threadId;
|
||||
private TextView subjectView;
|
||||
private TextView fromView;
|
||||
private TextView dateView;
|
||||
private boolean read;
|
||||
private ImageView contactPhotoImage;
|
||||
private Context context;
|
||||
private Set<Long> selectedThreads;
|
||||
private Recipients recipients;
|
||||
private long threadId;
|
||||
private TextView subjectView;
|
||||
private FromTextView fromView;
|
||||
private TextView dateView;
|
||||
private boolean read;
|
||||
private AvatarImageView contactPhotoImage;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
private int distributionType;
|
||||
@ -79,10 +79,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
this.subjectView = (TextView) findViewById(R.id.subject);
|
||||
this.fromView = (TextView) findViewById(R.id.from);
|
||||
this.fromView = (FromTextView) findViewById(R.id.from);
|
||||
this.dateView = (TextView) findViewById(R.id.date);
|
||||
|
||||
this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image);
|
||||
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
||||
|
||||
initializeContactWidgetVisibility();
|
||||
}
|
||||
@ -95,7 +94,7 @@ public class ConversationListItem extends RelativeLayout
|
||||
this.distributionType = thread.getDistributionType();
|
||||
|
||||
this.recipients.addListener(this);
|
||||
this.fromView.setText(RecipientViewUtil.formatFrom(context, recipients, read));
|
||||
this.fromView.setText(recipients, read);
|
||||
|
||||
this.subjectView.setText(Emoji.getInstance(context).emojify(thread.getDisplayBody(),
|
||||
Emoji.EMOJI_SMALL,
|
||||
@ -110,7 +109,7 @@ public class ConversationListItem extends RelativeLayout
|
||||
}
|
||||
|
||||
setBackground(read, batchMode);
|
||||
RecipientViewUtil.setContactPhoto(context, contactPhotoImage, recipients.getPrimaryRecipient(), true);
|
||||
this.contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), true);
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
@ -157,8 +156,8 @@ public class ConversationListItem extends RelativeLayout
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ConversationListItem.this.fromView.setText(RecipientViewUtil.formatFrom(context, recipients, read));
|
||||
RecipientViewUtil.setContactPhoto(context, contactPhotoImage, recipients.getPrimaryRecipient(), true);
|
||||
fromView.setText(recipients, read);
|
||||
contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -23,10 +23,11 @@ import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
@ -35,7 +36,6 @@ import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.RecipientViewUtil;
|
||||
|
||||
/**
|
||||
* A simple view to show the recipients of a message
|
||||
@ -47,12 +47,12 @@ public class MessageRecipientListItem extends RelativeLayout
|
||||
{
|
||||
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
|
||||
|
||||
private Recipient recipient;
|
||||
private TextView fromView;
|
||||
private TextView errorDescription;
|
||||
private Button conflictButton;
|
||||
private Button resendButton;
|
||||
private ImageView contactPhotoImage;
|
||||
private Recipient recipient;
|
||||
private FromTextView fromView;
|
||||
private TextView errorDescription;
|
||||
private Button conflictButton;
|
||||
private Button resendButton;
|
||||
private AvatarImageView contactPhotoImage;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
|
||||
@ -66,11 +66,11 @@ public class MessageRecipientListItem extends RelativeLayout
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
this.fromView = (TextView) findViewById(R.id.from);
|
||||
this.errorDescription = (TextView) findViewById(R.id.error_description);
|
||||
this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image);
|
||||
this.conflictButton = (Button) findViewById(R.id.conflict_button);
|
||||
this.resendButton = (Button) findViewById(R.id.resend_button);
|
||||
this.fromView = (FromTextView) findViewById(R.id.from);
|
||||
this.errorDescription = (TextView) findViewById(R.id.error_description);
|
||||
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
||||
this.conflictButton = (Button) findViewById(R.id.conflict_button);
|
||||
this.resendButton = (Button) findViewById(R.id.resend_button);
|
||||
}
|
||||
|
||||
public void set(final MasterSecret masterSecret,
|
||||
@ -81,9 +81,8 @@ public class MessageRecipientListItem extends RelativeLayout
|
||||
this.recipient = recipient;
|
||||
|
||||
recipient.addListener(this);
|
||||
fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipient));
|
||||
|
||||
RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipient, false);
|
||||
fromView.setText(recipient);
|
||||
contactPhotoImage.setAvatar(recipient, false);
|
||||
setIssueIndicators(masterSecret, record, isPushGroup);
|
||||
}
|
||||
|
||||
@ -160,8 +159,8 @@ public class MessageRecipientListItem extends RelativeLayout
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipient));
|
||||
RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipient, false);
|
||||
fromView.setText(recipient);
|
||||
contactPhotoImage.setAvatar(recipient, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -20,17 +20,13 @@ import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.makeramen.RoundedImageView;
|
||||
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.RecipientViewUtil;
|
||||
|
||||
/**
|
||||
* A simple view to show the recipients of an open conversation
|
||||
@ -42,12 +38,12 @@ public class ShareListItem extends RelativeLayout
|
||||
{
|
||||
private final static String TAG = ShareListItem.class.getSimpleName();
|
||||
|
||||
private Context context;
|
||||
private Recipients recipients;
|
||||
private long threadId;
|
||||
private TextView fromView;
|
||||
private Context context;
|
||||
private Recipients recipients;
|
||||
private long threadId;
|
||||
private FromTextView fromView;
|
||||
|
||||
private RoundedImageView contactPhotoImage;
|
||||
private AvatarImageView contactPhotoImage;
|
||||
|
||||
private final Handler handler = new Handler();
|
||||
private int distributionType;
|
||||
@ -64,8 +60,8 @@ public class ShareListItem extends RelativeLayout
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
this.fromView = (TextView) findViewById(R.id.from);
|
||||
this.contactPhotoImage = (RoundedImageView) findViewById(R.id.contact_photo_image);
|
||||
this.fromView = (FromTextView) findViewById(R.id.from);
|
||||
this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image);
|
||||
}
|
||||
|
||||
public void set(ThreadRecord thread) {
|
||||
@ -74,10 +70,10 @@ public class ShareListItem extends RelativeLayout
|
||||
this.distributionType = thread.getDistributionType();
|
||||
|
||||
this.recipients.addListener(this);
|
||||
this.fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipients));
|
||||
this.fromView.setText(recipients);
|
||||
|
||||
setBackground();
|
||||
RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, this.recipients.getPrimaryRecipient(), false);
|
||||
this.contactPhotoImage.setAvatar(this.recipients.getPrimaryRecipient(), false);
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
@ -110,8 +106,8 @@ public class ShareListItem extends RelativeLayout
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fromView.setText(RecipientViewUtil.formatFrom(getContext(), recipients));
|
||||
RecipientViewUtil.setContactPhoto(getContext(), contactPhotoImage, recipients.getPrimaryRecipient(), false);
|
||||
fromView.setText(recipients);
|
||||
contactPhotoImage.setAvatar(recipients.getPrimaryRecipient(), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,49 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.provider.ContactsContract;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public class AvatarImageView extends ImageView {
|
||||
|
||||
public AvatarImageView(Context context) {
|
||||
super(context);
|
||||
setScaleType(ScaleType.CENTER_INSIDE);
|
||||
}
|
||||
|
||||
public AvatarImageView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setScaleType(ScaleType.CENTER_INSIDE);
|
||||
}
|
||||
|
||||
public void setAvatar(Recipient recipient, boolean quickContactEnabled) {
|
||||
setImageDrawable(recipient.getContactPhoto());
|
||||
setAvatarClickHandler(recipient, quickContactEnabled);
|
||||
}
|
||||
|
||||
private void setAvatarClickHandler(final Recipient recipient, boolean quickContactEnabled) {
|
||||
if (!recipient.isGroupRecipient() && quickContactEnabled) {
|
||||
setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (recipient.getContactUri() != null) {
|
||||
ContactsContract.QuickContact.showQuickContact(getContext(), AvatarImageView.this, recipient.getContactUri(), ContactsContract.QuickContact.MODE_LARGE, null);
|
||||
} else {
|
||||
final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
|
||||
intent.putExtra(ContactsContract.Intents.Insert.PHONE, recipient.getNumber());
|
||||
intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
|
||||
getContext().startActivity(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
69
src/org/thoughtcrime/securesms/components/FromTextView.java
Normal file
69
src/org/thoughtcrime/securesms/components/FromTextView.java
Normal file
@ -0,0 +1,69 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
public class FromTextView extends TextView {
|
||||
|
||||
public FromTextView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public FromTextView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void setText(Recipient recipient) {
|
||||
setText(new Recipients(recipient));
|
||||
}
|
||||
|
||||
public void setText(Recipients recipients) {
|
||||
setText(recipients, true);
|
||||
}
|
||||
|
||||
public void setText(Recipients recipients, boolean read) {
|
||||
int attributes[] = new int[]{R.attr.conversation_list_item_count_color};
|
||||
TypedArray colors = getContext().obtainStyledAttributes(attributes);
|
||||
boolean isUnnamedGroup = recipients.isGroupRecipient() && TextUtils.isEmpty(recipients.getPrimaryRecipient().getName());
|
||||
|
||||
String fromString;
|
||||
|
||||
if (isUnnamedGroup) {
|
||||
fromString = getContext().getString(R.string.ConversationActivity_unnamed_group);
|
||||
} else {
|
||||
fromString = recipients.toShortString();
|
||||
}
|
||||
|
||||
int typeface;
|
||||
|
||||
if (isUnnamedGroup) {
|
||||
if (!read) typeface = Typeface.BOLD_ITALIC;
|
||||
else typeface = Typeface.ITALIC;
|
||||
} else if (!read) {
|
||||
typeface = Typeface.BOLD;
|
||||
} else {
|
||||
typeface = Typeface.NORMAL;
|
||||
}
|
||||
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(fromString);
|
||||
builder.setSpan(new StyleSpan(typeface), 0, builder.length(),
|
||||
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
colors.recycle();
|
||||
|
||||
setText(builder);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,15 +1,31 @@
|
||||
package org.thoughtcrime.securesms.contacts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.LayerDrawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.provider.ContactsContract;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.amulyakhare.textdrawable.util.ColorGenerator;
|
||||
import com.makeramen.RoundedDrawable;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -24,62 +40,56 @@ import java.util.Map;
|
||||
public class ContactPhotoFactory {
|
||||
private static final String TAG = ContactPhotoFactory.class.getSimpleName();
|
||||
|
||||
private static final ColorGenerator COLOR_GENERATOR = ColorGenerator.MATERIAL;
|
||||
private static final int UNKNOWN_COLOR = 0xff9E9E9E;
|
||||
|
||||
private static final Object defaultPhotoLock = new Object();
|
||||
private static final Object defaultGroupPhotoLock = new Object();
|
||||
private static final Object loadingPhotoLock = new Object();
|
||||
|
||||
private static Bitmap defaultContactPhoto;
|
||||
private static Bitmap defaultGroupContactPhoto;
|
||||
private static Drawable defaultContactPhoto;
|
||||
private static Drawable defaultGroupContactPhoto;
|
||||
private static Drawable loadingPhoto;
|
||||
|
||||
private static final Map<Uri,Bitmap> localUserContactPhotoCache =
|
||||
Collections.synchronizedMap(new LRUCache<Uri,Bitmap>(2));
|
||||
|
||||
private static final String[] CONTENT_URI_PROJECTION = new String[] {
|
||||
ContactsContract.Contacts._ID,
|
||||
ContactsContract.Contacts.DISPLAY_NAME,
|
||||
ContactsContract.Contacts.LOOKUP_KEY
|
||||
};
|
||||
public static Drawable getLoadingPhoto(Context context) {
|
||||
synchronized (loadingPhotoLock) {
|
||||
if (loadingPhoto == null)
|
||||
loadingPhoto = RoundedDrawable.fromDrawable(context.getResources().getDrawable(android.R.color.transparent));
|
||||
|
||||
return loadingPhoto;
|
||||
}
|
||||
}
|
||||
|
||||
public static Drawable getDefaultContactPhoto(@Nullable String name) {
|
||||
if (name != null && !name.isEmpty()) {
|
||||
return TextDrawable.builder().buildRound(String.valueOf(name.charAt(0)),
|
||||
COLOR_GENERATOR.getColor(name));
|
||||
}
|
||||
|
||||
public static Bitmap getDefaultContactPhoto(Context context) {
|
||||
synchronized (defaultPhotoLock) {
|
||||
if (defaultContactPhoto == null)
|
||||
defaultContactPhoto = BitmapFactory.decodeResource(context.getResources(),
|
||||
R.drawable.ic_contact_picture);
|
||||
defaultContactPhoto = TextDrawable.builder().buildRound("#", UNKNOWN_COLOR);
|
||||
|
||||
return defaultContactPhoto;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap getDefaultGroupPhoto(Context context) {
|
||||
public static Drawable getDefaultGroupPhoto(Context context) {
|
||||
synchronized (defaultGroupPhotoLock) {
|
||||
if (defaultGroupContactPhoto == null)
|
||||
defaultGroupContactPhoto = BitmapFactory.decodeResource(context.getResources(),
|
||||
R.drawable.ic_group_photo);
|
||||
return defaultGroupContactPhoto;
|
||||
}
|
||||
}
|
||||
if (defaultGroupContactPhoto == null) {
|
||||
Drawable background = TextDrawable.builder().buildRound(" ", UNKNOWN_COLOR);
|
||||
RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(context.getResources().getDrawable(R.drawable.ic_group_white_24dp));
|
||||
foreground.setScaleType(ImageView.ScaleType.CENTER);
|
||||
|
||||
public static Bitmap getLocalUserContactPhoto(Context context, Uri uri) {
|
||||
if (uri == null) return getDefaultContactPhoto(context);
|
||||
|
||||
Bitmap contactPhoto = localUserContactPhotoCache.get(uri);
|
||||
|
||||
if (contactPhoto == null) {
|
||||
Cursor cursor = context.getContentResolver().query(uri, CONTENT_URI_PROJECTION,
|
||||
null, null, null);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
contactPhoto = getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
|
||||
cursor.getLong(0) + ""));
|
||||
} else {
|
||||
contactPhoto = getDefaultContactPhoto(context);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
defaultGroupContactPhoto = new ExpandingLayerDrawable(new Drawable[] {background, foreground});
|
||||
}
|
||||
|
||||
localUserContactPhotoCache.put(uri, contactPhoto);
|
||||
return defaultGroupContactPhoto;
|
||||
}
|
||||
|
||||
return contactPhoto;
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
@ -91,25 +101,32 @@ public class ContactPhotoFactory {
|
||||
localUserContactPhotoCache.remove(recipient.getContactUri());
|
||||
}
|
||||
|
||||
public static Bitmap getContactPhoto(Context context, Uri uri) {
|
||||
public static Drawable getContactPhoto(Context context, Uri uri, String name) {
|
||||
final InputStream inputStream = getContactPhotoStream(context, uri);
|
||||
final int targetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
|
||||
Bitmap contactPhoto = null;
|
||||
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
contactPhoto = BitmapUtil.createScaledBitmap(inputStream,
|
||||
getContactPhotoStream(context, uri),
|
||||
targetSize,
|
||||
targetSize);
|
||||
return RoundedDrawable.fromBitmap(BitmapUtil.createScaledBitmap(inputStream,
|
||||
getContactPhotoStream(context, uri),
|
||||
targetSize,
|
||||
targetSize))
|
||||
.setScaleType(ImageView.ScaleType.CENTER_CROP)
|
||||
.setOval(true);
|
||||
} catch (BitmapDecodingException bde) {
|
||||
Log.w(TAG, bde);
|
||||
}
|
||||
}
|
||||
if (contactPhoto == null) {
|
||||
contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
}
|
||||
|
||||
return contactPhoto;
|
||||
return getDefaultContactPhoto(name);
|
||||
}
|
||||
|
||||
public static Drawable getGroupContactPhoto(Context context, @Nullable byte[] avatar) {
|
||||
if (avatar == null) return getDefaultGroupPhoto(context);
|
||||
|
||||
return RoundedDrawable.fromBitmap(BitmapFactory.decodeByteArray(avatar, 0, avatar.length))
|
||||
.setScaleType(ImageView.ScaleType.CENTER_CROP)
|
||||
.setOval(true);
|
||||
}
|
||||
|
||||
private static InputStream getContactPhotoStream(Context context, Uri uri) {
|
||||
@ -119,4 +136,21 @@ public class ContactPhotoFactory {
|
||||
return ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExpandingLayerDrawable extends LayerDrawable {
|
||||
|
||||
public ExpandingLayerDrawable(Drawable[] layers) {
|
||||
super(layers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ package org.thoughtcrime.securesms.contacts;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.provider.ContactsContract;
|
||||
import android.support.v4.widget.CursorAdapter;
|
||||
import android.text.Spannable;
|
||||
@ -73,7 +72,6 @@ public class ContactSelectionListAdapter extends CursorAdapter
|
||||
private final boolean multiSelect;
|
||||
private final LayoutInflater li;
|
||||
private final TypedArray drawables;
|
||||
private final Bitmap defaultPhoto;
|
||||
private final int scaledPhotoSize;
|
||||
|
||||
private final HashMap<Long, ContactAccessor.ContactData> selectedContacts = new HashMap<>();
|
||||
@ -84,7 +82,6 @@ public class ContactSelectionListAdapter extends CursorAdapter
|
||||
this.li = LayoutInflater.from(context);
|
||||
this.drawables = context.obtainStyledAttributes(STYLE_ATTRIBUTES);
|
||||
this.multiSelect = multiSelect;
|
||||
this.defaultPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
this.scaledPhotoSize = context.getResources().getDimensionPixelSize(R.dimen.contact_selection_photo_size);
|
||||
}
|
||||
|
||||
@ -180,7 +177,7 @@ public class ContactSelectionListAdapter extends CursorAdapter
|
||||
numberLabelSpan.setSpan(new ForegroundColorSpan(drawables.getColor(2, 0xff444444)), contactData.number.length(), numberWithLabel.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
holder.number.setText(numberLabelSpan);
|
||||
}
|
||||
holder.contactPhoto.setImageBitmap(defaultPhoto);
|
||||
holder.contactPhoto.setImageDrawable(ContactPhotoFactory.getLoadingPhoto(context));
|
||||
if (contactData.id > -1) loadBitmap(contactData.number, holder.contactPhoto);
|
||||
}
|
||||
|
||||
@ -229,11 +226,14 @@ public class ContactSelectionListAdapter extends CursorAdapter
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME -- It should be unnecessary to duplicate the existing asynchronous resolution
|
||||
// infrastructure we've built for Recipient objects here.
|
||||
|
||||
public void loadBitmap(String number, ImageView imageView) {
|
||||
if (cancelPotentialWork(number, imageView)) {
|
||||
final BitmapWorkerRunnable runnable = new BitmapWorkerRunnable(context, imageView, defaultPhoto, number, scaledPhotoSize);
|
||||
final BitmapWorkerRunnable runnable = new BitmapWorkerRunnable(context, imageView, number, scaledPhotoSize);
|
||||
final TaggedFutureTask<?> task = new TaggedFutureTask<Void>(runnable, null, number);
|
||||
final AsyncDrawable asyncDrawable = new AsyncDrawable(defaultPhoto, task);
|
||||
final AsyncDrawable asyncDrawable = new AsyncDrawable(task);
|
||||
|
||||
imageView.setImageDrawable(asyncDrawable);
|
||||
if (!task.isCancelled()) photoResolver.execute(new FutureTask<Void>(task, null));
|
||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.Release;
|
||||
@ -74,7 +75,7 @@ public class AvatarDownloadJob extends MasterSecretJob {
|
||||
|
||||
Recipient groupRecipient = RecipientFactory.getRecipientsFromString(context, GroupUtil.getEncodedId(groupId), true)
|
||||
.getPrimaryRecipient();
|
||||
groupRecipient.setContactPhoto(avatar);
|
||||
groupRecipient.setContactPhoto(new BitmapDrawable(avatar));
|
||||
}
|
||||
} catch (InvalidMessageException | BitmapDecodingException | NonSuccessfulResponseCodeException e) {
|
||||
Log.w(TAG, e);
|
||||
|
@ -24,9 +24,9 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
@ -181,9 +181,9 @@ public class MessageNotifier {
|
||||
List<NotificationItem> notifications = notificationState.getNotifications();
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
|
||||
Recipient recipient = notifications.get(0).getIndividualRecipient();
|
||||
Bitmap recipientPhoto = recipient.getContactPhoto();
|
||||
Drawable recipientPhoto = recipient.getContactPhoto();
|
||||
|
||||
if (recipientPhoto != null) builder.setLargeIcon(BitmapUtil.getCircleBitmap(recipientPhoto));
|
||||
if (recipientPhoto != null) builder.setLargeIcon(BitmapUtil.createFromDrawable(recipientPhoto));
|
||||
builder.setSmallIcon(R.drawable.icon_notification);
|
||||
builder.setColor(context.getResources().getColor(R.color.textsecure_primary));
|
||||
builder.setContentTitle(recipient.toShortString());
|
||||
|
@ -1,120 +0,0 @@
|
||||
package org.thoughtcrime.securesms.recipients;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
|
||||
/**
|
||||
* Utility class to generate avatars for contacts who don't have a contact
|
||||
* picture set.
|
||||
*
|
||||
* @author Lukas Barth
|
||||
*/
|
||||
public class AvatarGenerator {
|
||||
|
||||
public static Bitmap generateFor(Context context, Recipient recipient) {
|
||||
if ((recipient == null) || (recipient.getName() == null)) {
|
||||
return ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
}
|
||||
|
||||
final int size = ContactPhotoFactory.getDefaultContactPhoto(context).getHeight();
|
||||
final Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
final Canvas canvas = new Canvas(output);
|
||||
final int color = getColorForRecipient(recipient, context);
|
||||
final Paint paint = new Paint();
|
||||
final int innerRectOffset = (int) Math.ceil((size - Math.sqrt(2) * (size / 2)) / 2);
|
||||
final Rect innerRect = new Rect(innerRectOffset, innerRectOffset,
|
||||
size - innerRectOffset, size - innerRectOffset);
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(color);
|
||||
canvas.drawCircle(size / 2, size / 2, size / 2, paint);
|
||||
|
||||
paint.setColor(Color.WHITE);
|
||||
Typeface robotoLightTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto-Light.ttf");
|
||||
paint.setTypeface(robotoLightTypeface);
|
||||
setFontSize(innerRect, paint);
|
||||
|
||||
paint.setTextAlign(Paint.Align.CENTER);
|
||||
|
||||
int initialIndex = 0;
|
||||
char[] contactName = recipient.getName().toCharArray();
|
||||
|
||||
if (contactName.length == 0) {
|
||||
contactName = new char[]{'?'};
|
||||
initialIndex = 0;
|
||||
} else {
|
||||
while ((! Character.isLetter(contactName[initialIndex]))) {
|
||||
initialIndex ++;
|
||||
|
||||
if (initialIndex >= contactName.length) {
|
||||
contactName[0] = '?';
|
||||
initialIndex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect textBounds = new Rect();
|
||||
paint.getTextBounds(contactName, initialIndex, 1, textBounds);
|
||||
|
||||
int bottomOffset = (innerRect.height() - textBounds.height()) / 2;
|
||||
|
||||
canvas.drawText(Character.toString(contactName[initialIndex]),
|
||||
innerRect.centerX(), innerRect.bottom - bottomOffset, paint);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
private static int getColorForRecipient(Recipient recipient, Context context) {
|
||||
if ((recipient == null) || (recipient.getName() == null)) {
|
||||
return Color.WHITE;
|
||||
}
|
||||
|
||||
long nameHash = recipient.getName().hashCode();
|
||||
Resources res = context.getResources();
|
||||
TypedArray colorArray = res.obtainTypedArray(R.array.avatar_colors);
|
||||
int index = Math.abs((int) (nameHash % colorArray.length()));
|
||||
int color = colorArray.getColor(index, Color.BLACK);
|
||||
|
||||
colorArray.recycle();
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
private static int setFontSize(Rect textRect, Paint paint) {
|
||||
boolean overflow = false;
|
||||
int currentSize = 0;
|
||||
|
||||
while (!overflow) {
|
||||
currentSize++;
|
||||
paint.setTextSize(currentSize);
|
||||
|
||||
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
|
||||
int textHeight = fontMetrics.descent - fontMetrics.ascent;
|
||||
|
||||
if (textHeight > textRect.height()) {
|
||||
overflow = true;
|
||||
}
|
||||
}
|
||||
|
||||
currentSize--;
|
||||
|
||||
currentSize *= 1.2;
|
||||
|
||||
paint.setTextSize(currentSize);
|
||||
|
||||
return currentSize;
|
||||
}
|
||||
}
|
@ -18,13 +18,14 @@ package org.thoughtcrime.securesms.recipients;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
|
||||
import java.util.HashSet;
|
||||
@ -33,25 +34,22 @@ public class Recipient {
|
||||
|
||||
private final static String TAG = Recipient.class.getSimpleName();
|
||||
|
||||
private final HashSet<RecipientModifiedListener> listeners = new HashSet<RecipientModifiedListener>();
|
||||
private final HashSet<RecipientModifiedListener> listeners = new HashSet<>();
|
||||
|
||||
private final long recipientId;
|
||||
|
||||
private String number;
|
||||
private String name;
|
||||
|
||||
private Bitmap contactPhoto;
|
||||
private Bitmap generatedAvatar;
|
||||
private Drawable contactPhoto;
|
||||
private Uri contactUri;
|
||||
|
||||
private Uri contactUri;
|
||||
|
||||
Recipient(String number, Bitmap contactPhoto,
|
||||
Recipient(String number, Drawable contactPhoto,
|
||||
long recipientId, ListenableFutureTask<RecipientDetails> future)
|
||||
{
|
||||
this.number = number;
|
||||
this.contactPhoto = contactPhoto;
|
||||
this.recipientId = recipientId;
|
||||
this.generatedAvatar = null;
|
||||
|
||||
future.addListener(new FutureTaskListener<RecipientDetails>() {
|
||||
@Override
|
||||
@ -81,7 +79,7 @@ public class Recipient {
|
||||
});
|
||||
}
|
||||
|
||||
Recipient(String name, String number, long recipientId, Uri contactUri, Bitmap contactPhoto) {
|
||||
Recipient(String name, String number, long recipientId, Uri contactUri, Drawable contactPhoto) {
|
||||
this.number = number;
|
||||
this.recipientId = recipientId;
|
||||
this.contactUri = contactUri;
|
||||
@ -93,7 +91,7 @@ public class Recipient {
|
||||
return this.contactUri;
|
||||
}
|
||||
|
||||
public synchronized void setContactPhoto(Bitmap bitmap) {
|
||||
public synchronized void setContactPhoto(Drawable bitmap) {
|
||||
this.contactPhoto = bitmap;
|
||||
notifyListeners();
|
||||
}
|
||||
@ -143,20 +141,13 @@ public class Recipient {
|
||||
return (name == null ? number : name);
|
||||
}
|
||||
|
||||
public synchronized Bitmap getContactPhoto() {
|
||||
public synchronized Drawable getContactPhoto() {
|
||||
return contactPhoto;
|
||||
}
|
||||
|
||||
public synchronized Bitmap getGeneratedAvatar(Context context) {
|
||||
if (this.generatedAvatar == null)
|
||||
this.generatedAvatar = AvatarGenerator.generateFor(context, this);
|
||||
|
||||
return this.generatedAvatar;
|
||||
}
|
||||
|
||||
public static Recipient getUnknownRecipient(Context context) {
|
||||
return new Recipient("Unknown", "Unknown", -1, null,
|
||||
ContactPhotoFactory.getDefaultContactPhoto(context));
|
||||
ContactPhotoFactory.getDefaultContactPhoto(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -174,7 +165,7 @@ public class Recipient {
|
||||
return 31 + (int)this.recipientId;
|
||||
}
|
||||
|
||||
public static interface RecipientModifiedListener {
|
||||
public interface RecipientModifiedListener {
|
||||
public void onModified(Recipient recipient);
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ package org.thoughtcrime.securesms.recipients;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.provider.ContactsContract.Contacts;
|
||||
import android.provider.ContactsContract.PhoneLookup;
|
||||
@ -29,11 +28,10 @@ import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
|
||||
import org.thoughtcrime.securesms.database.CanonicalAddressDatabase;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.LRUCache;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
@ -75,9 +73,9 @@ public class RecipientProvider {
|
||||
if (details != null) {
|
||||
recipient = new Recipient(details.name, details.number, recipientId, details.contactUri, details.avatar);
|
||||
} else {
|
||||
final Bitmap defaultPhoto = isGroupRecipient
|
||||
final Drawable defaultPhoto = isGroupRecipient
|
||||
? ContactPhotoFactory.getDefaultGroupPhoto(context)
|
||||
: ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
: ContactPhotoFactory.getDefaultContactPhoto(null);
|
||||
|
||||
recipient = new Recipient(null, number, recipientId, null, defaultPhoto);
|
||||
}
|
||||
@ -100,16 +98,16 @@ public class RecipientProvider {
|
||||
}
|
||||
};
|
||||
|
||||
ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<RecipientDetails>(task);
|
||||
ListenableFutureTask<RecipientDetails> future = new ListenableFutureTask<>(task);
|
||||
|
||||
asyncRecipientResolver.submit(future);
|
||||
|
||||
Bitmap contactPhoto;
|
||||
Drawable contactPhoto;
|
||||
|
||||
if (isGroupRecipient) {
|
||||
contactPhoto = ContactPhotoFactory.getDefaultGroupPhoto(context);
|
||||
} else {
|
||||
contactPhoto = ContactPhotoFactory.getDefaultContactPhoto(context);
|
||||
contactPhoto = ContactPhotoFactory.getLoadingPhoto(context);
|
||||
}
|
||||
|
||||
Recipient recipient = new Recipient(number, contactPhoto, recipientId, future);
|
||||
@ -134,9 +132,10 @@ public class RecipientProvider {
|
||||
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
|
||||
Bitmap contactPhoto = ContactPhotoFactory.getContactPhoto(context, Uri.withAppendedPath(Contacts.CONTENT_URI,
|
||||
cursor.getLong(2)+""));
|
||||
Uri contactUri = Contacts.getLookupUri(cursor.getLong(2), cursor.getString(1));
|
||||
Drawable contactPhoto = ContactPhotoFactory.getContactPhoto(context,
|
||||
Uri.withAppendedPath(Contacts.CONTENT_URI, cursor.getLong(2)+""),
|
||||
cursor.getString(0));
|
||||
return new RecipientDetails(cursor.getString(0), cursor.getString(3), contactUri, contactPhoto);
|
||||
}
|
||||
} finally {
|
||||
@ -144,7 +143,7 @@ public class RecipientProvider {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return null;
|
||||
return new RecipientDetails(null, number, null, ContactPhotoFactory.getDefaultContactPhoto(null));
|
||||
}
|
||||
|
||||
private RecipientDetails getGroupRecipientDetails(Context context, String groupId) {
|
||||
@ -153,12 +152,7 @@ public class RecipientProvider {
|
||||
.getGroup(GroupUtil.getDecodedId(groupId));
|
||||
|
||||
if (record != null) {
|
||||
byte[] avatarBytes = record.getAvatar();
|
||||
Bitmap avatar;
|
||||
|
||||
if (avatarBytes == null) avatar = ContactPhotoFactory.getDefaultGroupPhoto(context);
|
||||
else avatar = BitmapFactory.decodeByteArray(avatarBytes, 0, avatarBytes.length);
|
||||
|
||||
Drawable avatar = ContactPhotoFactory.getGroupContactPhoto(context, record.getAvatar());
|
||||
return new RecipientDetails(record.getTitle(), groupId, null, avatar);
|
||||
}
|
||||
|
||||
@ -170,12 +164,12 @@ public class RecipientProvider {
|
||||
}
|
||||
|
||||
public static class RecipientDetails {
|
||||
public final String name;
|
||||
public final String number;
|
||||
public final Bitmap avatar;
|
||||
public final Uri contactUri;
|
||||
public final String name;
|
||||
public final String number;
|
||||
public final Drawable avatar;
|
||||
public final Uri contactUri;
|
||||
|
||||
public RecipientDetails(String name, String number, Uri contactUri, Bitmap avatar) {
|
||||
public RecipientDetails(String name, String number, Uri contactUri, Drawable avatar) {
|
||||
this.name = name;
|
||||
this.number = number;
|
||||
this.avatar = avatar;
|
||||
@ -183,4 +177,5 @@ public class RecipientProvider {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -12,6 +12,8 @@ import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@ -253,4 +255,23 @@ public class BitmapUtil {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static Bitmap createFromDrawable(Drawable drawable) {
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable)drawable).getBitmap();
|
||||
}
|
||||
|
||||
int width = drawable.getIntrinsicWidth();
|
||||
width = width > 0 ? width : 1;
|
||||
|
||||
int height = drawable.getIntrinsicHeight();
|
||||
height = height > 0 ? height : 1;
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.DrawableContainer;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.makeramen.RoundedDrawable;
|
||||
@ -38,49 +39,42 @@ import java.lang.ref.WeakReference;
|
||||
public class BitmapWorkerRunnable implements Runnable {
|
||||
private final static String TAG = BitmapWorkerRunnable.class.getSimpleName();
|
||||
|
||||
private final Bitmap defaultPhoto;
|
||||
|
||||
private final WeakReference<ImageView> imageViewReference;
|
||||
private final Context context;
|
||||
private final int size;
|
||||
public final String number;
|
||||
|
||||
public BitmapWorkerRunnable(Context context, ImageView imageView, Bitmap defaultPhoto, String number, int size) {
|
||||
public BitmapWorkerRunnable(Context context, ImageView imageView, String number, int size) {
|
||||
this.imageViewReference = new WeakReference<>(imageView);
|
||||
this.context = context;
|
||||
this.defaultPhoto = defaultPhoto;
|
||||
this.size = size;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final Recipient recipient = RecipientFactory.getRecipientsFromString(context, number, false).getPrimaryRecipient();
|
||||
final Bitmap contactPhoto = recipient.getContactPhoto();
|
||||
if (defaultPhoto == contactPhoto) {
|
||||
return;
|
||||
}
|
||||
if (recipient.getContactPhoto() != null) {
|
||||
final Recipient recipient = RecipientFactory.getRecipientsFromString(context, number, false).getPrimaryRecipient();
|
||||
final Drawable contactPhoto = recipient.getContactPhoto();
|
||||
|
||||
if (contactPhoto != null) {
|
||||
final ImageView imageView = imageViewReference.get();
|
||||
final TaggedFutureTask<?> bitmapWorkerTask = AsyncDrawable.getBitmapWorkerTask(imageView);
|
||||
|
||||
if (bitmapWorkerTask.getTag().equals(number) && imageView != null) {
|
||||
final BitmapDrawable drawable = new BitmapDrawable(context.getResources(), recipient.getContactPhoto());
|
||||
imageView.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
imageView.setImageDrawable(drawable);
|
||||
imageView.setImageDrawable(contactPhoto);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncDrawable extends RoundedDrawable {
|
||||
public static class AsyncDrawable extends BitmapDrawable {
|
||||
private final WeakReference<TaggedFutureTask<?>> bitmapWorkerTaskReference;
|
||||
|
||||
public AsyncDrawable(Bitmap bitmap, TaggedFutureTask<?> bitmapWorkerTask) {
|
||||
super(bitmap);
|
||||
public AsyncDrawable(TaggedFutureTask<?> bitmapWorkerTask) {
|
||||
bitmapWorkerTaskReference =
|
||||
new WeakReference<TaggedFutureTask<?>>(bitmapWorkerTask);
|
||||
}
|
||||
|
@ -1,83 +0,0 @@
|
||||
package org.thoughtcrime.securesms.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.provider.Contacts.Intents;
|
||||
import android.provider.ContactsContract.QuickContact;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
|
||||
public class RecipientViewUtil {
|
||||
public static CharSequence formatFrom(Context context, Recipient recipient) {
|
||||
return formatFrom(context, new Recipients(recipient));
|
||||
}
|
||||
|
||||
public static CharSequence formatFrom(Context context, Recipients from) {
|
||||
return formatFrom(context, from, true);
|
||||
}
|
||||
|
||||
public static CharSequence formatFrom(Context context, Recipients from, boolean read) {
|
||||
int attributes[] = new int[] {R.attr.conversation_list_item_count_color};
|
||||
TypedArray colors = context.obtainStyledAttributes(attributes);
|
||||
|
||||
final String fromString;
|
||||
final boolean isUnnamedGroup = from.isGroupRecipient() && TextUtils.isEmpty(from.getPrimaryRecipient().getName());
|
||||
if (isUnnamedGroup) {
|
||||
fromString = context.getString(R.string.ConversationActivity_unnamed_group);
|
||||
} else {
|
||||
fromString = from.toShortString();
|
||||
}
|
||||
SpannableStringBuilder builder = new SpannableStringBuilder(fromString);
|
||||
|
||||
final int typeface;
|
||||
if (isUnnamedGroup) {
|
||||
if (!read) typeface = Typeface.BOLD_ITALIC;
|
||||
else typeface = Typeface.ITALIC;
|
||||
} else if (!read) {
|
||||
typeface = Typeface.BOLD;
|
||||
} else {
|
||||
typeface = Typeface.NORMAL;
|
||||
}
|
||||
|
||||
builder.setSpan(new StyleSpan(typeface), 0, builder.length(),
|
||||
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||
|
||||
|
||||
colors.recycle();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static void setContactPhoto(final Context context, final ImageView imageView, final Recipient recipient, boolean showQuickContact) {
|
||||
if (recipient == null) return;
|
||||
|
||||
imageView.setImageBitmap(recipient.getContactPhoto());
|
||||
|
||||
if (!recipient.isGroupRecipient() && showQuickContact) {
|
||||
imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (recipient.getContactUri() != null) {
|
||||
QuickContact.showQuickContact(context, imageView, recipient.getContactUri(), QuickContact.MODE_LARGE, null);
|
||||
} else {
|
||||
Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, Uri.fromParts("tel", recipient.getNumber(), null));
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
imageView.setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user