From fb9f16ad29bcc54facdc2cc67ed8b9f6e54fcf8c Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Tue, 23 Jun 2015 15:10:50 -0700 Subject: [PATCH] Colorize conversations. // FREEBIE --- .../push_contact_selection_list_item.xml | 20 ++-- .../securesms/ConversationActivity.java | 22 ++++ .../securesms/components/AvatarImageView.java | 6 +- .../contacts/ContactSelectionListItem.java | 74 ++++++------ .../contacts/avatars/BitmapContactPhoto.java | 2 +- .../contacts/avatars/ContactColors.java | 107 ++++++++++++++++++ .../contacts/avatars/ContactPhoto.java | 2 +- .../contacts/avatars/ContactPhotoFactory.java | 6 +- .../avatars/GeneratedContactPhoto.java | 10 +- .../avatars/ResourceContactPhoto.java | 8 +- .../avatars/TransparentContactPhoto.java | 2 +- .../database/RecipientPreferenceDatabase.java | 35 ++++-- .../notifications/MessageNotifier.java | 5 +- .../securesms/recipients/Recipient.java | 3 +- .../recipients/RecipientProvider.java | 14 ++- .../securesms/recipients/Recipients.java | 28 ++++- 16 files changed, 250 insertions(+), 94 deletions(-) create mode 100644 src/org/thoughtcrime/securesms/contacts/avatars/ContactColors.java diff --git a/res/layout/push_contact_selection_list_item.xml b/res/layout/push_contact_selection_list_item.xml index 60308d7e82..93cd8aad53 100644 --- a/res/layout/push_contact_selection_list_item.xml +++ b/res/layout/push_contact_selection_list_item.xml @@ -6,16 +6,16 @@ android:layout_height="?android:attr/listPreferredItemHeight" android:paddingRight="50dp"> - + color) { + int colorPrimary = getResources().getColor(R.color.textsecure_primary); + int colorPrimaryDark = getResources().getColor(R.color.textsecure_primary_dark); + + getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.or(colorPrimary))); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (color.isPresent()) getWindow().setStatusBarColor(ContactColors.getStatusTinted(color.get()).or(colorPrimaryDark)); + else getWindow().setStatusBarColor(colorPrimaryDark); + } + } + private void setBlockedUserState(Recipients recipients) { if (recipients.isBlocked()) { unblockButton.setVisibility(View.VISIBLE); diff --git a/src/org/thoughtcrime/securesms/components/AvatarImageView.java b/src/org/thoughtcrime/securesms/components/AvatarImageView.java index eb3626e1d4..16ac26bb92 100644 --- a/src/org/thoughtcrime/securesms/components/AvatarImageView.java +++ b/src/org/thoughtcrime/securesms/components/AvatarImageView.java @@ -8,6 +8,7 @@ import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; +import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientFactory; @@ -27,10 +28,11 @@ public class AvatarImageView extends ImageView { public void setAvatar(@Nullable Recipients recipients, boolean quickContactEnabled) { if (recipients != null) { - setImageDrawable(recipients.getContactPhoto().asDrawable(getContext())); + int backgroundColor = recipients.getColor().or(ContactColors.UNKNOWN_COLOR); + setImageDrawable(recipients.getContactPhoto().asDrawable(getContext(), backgroundColor)); setAvatarClickHandler(recipients, quickContactEnabled); } else { - setImageDrawable(ContactPhotoFactory.getDefaultContactPhoto(null).asDrawable(getContext())); + setImageDrawable(ContactPhotoFactory.getDefaultContactPhoto(null).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR)); setOnClickListener(null); } } diff --git a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java index 3901783744..0368558596 100644 --- a/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java +++ b/src/org/thoughtcrime/securesms/contacts/ContactSelectionListItem.java @@ -1,29 +1,28 @@ package org.thoughtcrime.securesms.contacts; import android.content.Context; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import android.widget.CheckBox; -import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.components.AvatarImageView; import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.Recipients; -public class ContactSelectionListItem extends RelativeLayout implements Recipient.RecipientModifiedListener { +public class ContactSelectionListItem extends RelativeLayout implements Recipients.RecipientsModifiedListener { - private ImageView contactPhotoImage; - private TextView numberView; - private TextView nameView; - private TextView labelView; - private CheckBox checkBox; + private AvatarImageView contactPhotoImage; + private TextView numberView; + private TextView nameView; + private TextView labelView; + private CheckBox checkBox; - private long id; - private String number; - private Recipient recipient; + private long id; + private String number; + private Recipients recipients; public ContactSelectionListItem(Context context) { super(context); @@ -39,11 +38,12 @@ public class ContactSelectionListItem extends RelativeLayout implements Recipien @Override protected void onFinishInflate() { - this.contactPhotoImage = (ImageView) findViewById(R.id.contact_photo_image); - this.numberView = (TextView) findViewById(R.id.number); - this.labelView = (TextView) findViewById(R.id.label); - this.nameView = (TextView) findViewById(R.id.name); - this.checkBox = (CheckBox) findViewById(R.id.check_box); + super.onFinishInflate(); + this.contactPhotoImage = (AvatarImageView) findViewById(R.id.contact_photo_image); + this.numberView = (TextView) findViewById(R.id.number); + this.labelView = (TextView) findViewById(R.id.label); + this.nameView = (TextView) findViewById(R.id.name); + this.checkBox = (CheckBox) findViewById(R.id.check_box); } public void set(long id, int type, String name, String number, String label, int color, boolean multiSelect) { @@ -51,15 +51,15 @@ public class ContactSelectionListItem extends RelativeLayout implements Recipien this.number = number; if (number != null) { - this.recipient = RecipientFactory.getRecipientsFromString(getContext(), number, true) - .getPrimaryRecipient(); + this.recipients = RecipientFactory.getRecipientsFromString(getContext(), number, true); + this.recipients.addListener(this); } this.nameView.setTextColor(color); this.numberView.setTextColor(color); + this.contactPhotoImage.setAvatar(recipients, false); setText(type, name, number, label); - setContactPhotoImage(recipient); if (multiSelect) this.checkBox.setVisibility(View.VISIBLE); else this.checkBox.setVisibility(View.GONE); @@ -70,9 +70,9 @@ public class ContactSelectionListItem extends RelativeLayout implements Recipien } public void unbind() { - if (recipient != null) { - recipient.removeListener(this); - recipient = null; + if (recipients != null) { + recipients.removeListener(this); + recipients = null; } } @@ -95,33 +95,23 @@ public class ContactSelectionListItem extends RelativeLayout implements Recipien this.nameView.setText(name); } - private void setContactPhotoImage(@Nullable Recipient recipient) { - if (recipient!= null) { - contactPhotoImage.setImageDrawable(recipient.getContactPhoto().asDrawable(getContext())); - recipient.addListener(this); - } else { - contactPhotoImage.setImageDrawable(null); - } + public long getContactId() { + return id; + } + + public String getNumber() { + return number; } @Override - public void onModified(final Recipient recipient) { - if (this.recipient == recipient) { - recipient.removeListener(this); + public void onModified(final Recipients recipients) { + if (this.recipients == recipients) { this.contactPhotoImage.post(new Runnable() { @Override public void run() { - contactPhotoImage.setImageDrawable(recipient.getContactPhoto().asDrawable(getContext())); + contactPhotoImage.setAvatar(recipients, false); } }); } } - - public long getContactId() { - return id; - } - - public String getNumber() { - return number; - } } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java index bd4f74b309..31025722e7 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/BitmapContactPhoto.java @@ -16,7 +16,7 @@ public class BitmapContactPhoto implements ContactPhoto { } @Override - public Drawable asDrawable(Context context) { + public Drawable asDrawable(Context context, int background) { return RoundedDrawable.fromBitmap(bitmap) .setScaleType(ImageView.ScaleType.CENTER_CROP) .setOval(true); diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ContactColors.java b/src/org/thoughtcrime/securesms/contacts/avatars/ContactColors.java new file mode 100644 index 0000000000..51ff3349e6 --- /dev/null +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ContactColors.java @@ -0,0 +1,107 @@ +package org.thoughtcrime.securesms.contacts.avatars; + +import android.support.annotation.NonNull; +import android.util.SparseIntArray; + +import com.amulyakhare.textdrawable.util.ColorGenerator; + +import org.whispersystems.libaxolotl.util.guava.Optional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class ContactColors { + + public static final int UNKNOWN_COLOR = 0xff9E9E9E; + + private static final int RED_300 = 0xffE57373; + private static final int RED_700 = 0xFFD32F2F; + private static final int PINK_300 = 0xffF06292; + private static final int PINK_700 = 0xFFC2185B; + private static final int PURPLE_300 = 0xffBA68C8; + private static final int PURPLE_700 = 0xFF7B1FA2; + private static final int DEEP_PURPLE_300 = 0xff9575CD; + private static final int DEEP_PURPLE_700 = 0xFF512DA8; + private static final int INDIGO_300 = 0xff7986CB; + private static final int INDIGO_700 = 0xFF303F9F; + private static final int BLUE_300 = 0xff64B5F6; + private static final int BLUE_700 = 0xFF1976D2; + private static final int LIGHT_BLUE_300 = 0xff4FC3F7; + private static final int LIGHT_BLUE_700 = 0xFF0288D1; + private static final int CYAN_300 = 0xff4DD0E1; + private static final int CYAN_700 = 0xFF0097A7; + private static final int TEAL_300 = 0xFF4DB6AC; + private static final int TEAL_700 = 0xFF00796B; + private static final int GREEN_300 = 0xFF81C784; + private static final int GREEN_700 = 0xFF388E3C; + private static final int LIGHT_GREEN_300 = 0xFFAED581; + private static final int LIGHT_GREEN_700 = 0xFF689F38; + private static final int LIME_300 = 0xFFDCE775; + private static final int LIME_700 = 0xFFAFB42B; + private static final int YELLOW_300 = 0xFFFFF176; + private static final int YELLOW_700 = 0xFFFBC02D; + private static final int AMBER_300 = 0xFFFFD54F; + private static final int AMBER_700 = 0xFFFFA000; + private static final int ORANGE_300 = 0xFFFFB74D; + private static final int ORANGE_700 = 0xFFF57C00; + private static final int DEEP_ORANGE_300 = 0xFFFF8A65; + private static final int DEEP_ORANGE_700 = 0xFFE64A19; + private static final int BROWN_300 = 0xFFA1887F; + private static final int BROWN_700 = 0xFF5D4037; + private static final int BLUE_GREY_300 = 0xFF90A4AE; + private static final int BLUE_GREY_700 = 0xFF455A64; + + private static final List MATERIAL_300 = new ArrayList<>(Arrays.asList( + RED_300, + PINK_300, + PURPLE_300, + DEEP_PURPLE_300, + INDIGO_300, + BLUE_300, + LIGHT_BLUE_300, + CYAN_300, + TEAL_300, + GREEN_300, + LIGHT_GREEN_300, + LIME_300, + AMBER_300, + ORANGE_300, + DEEP_ORANGE_300, + BROWN_300, + BLUE_GREY_300) + ); + + private static final SparseIntArray MATERIAL_300_TO_700 = new SparseIntArray() {{ + put(RED_300, RED_700); + put(PINK_300, PINK_700); + put(PURPLE_300, PURPLE_700); + put(DEEP_PURPLE_300, DEEP_PURPLE_700); + put(INDIGO_300, INDIGO_700); + put(BLUE_300, BLUE_700); + put(LIGHT_BLUE_300, LIGHT_BLUE_700); + put(CYAN_300, CYAN_700); + put(TEAL_300, TEAL_700); + put(GREEN_300, GREEN_700); + put(LIGHT_GREEN_300, LIGHT_GREEN_700); + put(LIME_300, LIME_700); + put(AMBER_300, AMBER_700); + put(ORANGE_300, ORANGE_700); + put(DEEP_ORANGE_300, DEEP_ORANGE_700); + put(BROWN_300, BROWN_700); + put(BLUE_GREY_300, BLUE_GREY_700); + }}; + + + private static final ColorGenerator MATERIAL_GENERATOR = ColorGenerator.create(MATERIAL_300); + + public static int generateFor(@NonNull String name) { + return MATERIAL_GENERATOR.getColor(name); + } + + public static Optional getStatusTinted(int color) { + int statusTinted = MATERIAL_300_TO_700.get(color, -1); + return statusTinted == -1 ? Optional.absent() : Optional.of(statusTinted); + } + +} diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java index f79e7bce4e..4d389900aa 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhoto.java @@ -5,7 +5,7 @@ import android.graphics.drawable.Drawable; public interface ContactPhoto { - public Drawable asDrawable(Context context); + public Drawable asDrawable(Context context, int background); } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java index 094b45842d..79816268e2 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ContactPhotoFactory.java @@ -19,19 +19,17 @@ import java.io.InputStream; public class ContactPhotoFactory { private static final String TAG = ContactPhotoFactory.class.getSimpleName(); - private static final int UNKNOWN_COLOR = 0xff9E9E9E; - public static ContactPhoto getLoadingPhoto() { return new TransparentContactPhoto(); } public static ContactPhoto getDefaultContactPhoto(@Nullable String name) { if (!TextUtils.isEmpty(name)) return new GeneratedContactPhoto(name); - else return new GeneratedContactPhoto("#", UNKNOWN_COLOR); + else return new GeneratedContactPhoto("#"); } public static ContactPhoto getDefaultGroupPhoto() { - return new ResourceContactPhoto(R.drawable.ic_group_white_24dp, UNKNOWN_COLOR); + return new ResourceContactPhoto(R.drawable.ic_group_white_24dp); } public static ContactPhoto getContactPhoto(Context context, Uri uri, String name) { diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java index b45b8f3747..3325368597 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/GeneratedContactPhoto.java @@ -12,19 +12,13 @@ import org.thoughtcrime.securesms.R; public class GeneratedContactPhoto implements ContactPhoto { private final String name; - private final int color; GeneratedContactPhoto(@NonNull String name) { - this(name, ColorGenerator.MATERIAL.getColor(name)); - } - - GeneratedContactPhoto(@NonNull String name, int color) { this.name = name; - this.color = color; } @Override - public Drawable asDrawable(Context context) { + public Drawable asDrawable(Context context, int background) { int targetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); return TextDrawable.builder() @@ -32,6 +26,6 @@ public class GeneratedContactPhoto implements ContactPhoto { .width(targetSize) .height(targetSize) .endConfig() - .buildRound(String.valueOf(name.charAt(0)), color); + .buildRound(String.valueOf(name.charAt(0)), background); } } diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java index 9df25f46f5..d352300de1 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/ResourceContactPhoto.java @@ -11,16 +11,14 @@ import com.makeramen.roundedimageview.RoundedDrawable; public class ResourceContactPhoto implements ContactPhoto { private final int resourceId; - private final int color; - ResourceContactPhoto(int resourceId, int color) { + ResourceContactPhoto(int resourceId) { this.resourceId = resourceId; - this.color = color; } @Override - public Drawable asDrawable(Context context) { - Drawable background = TextDrawable.builder().buildRound(" ", color); + public Drawable asDrawable(Context context, int backgroundColor) { + Drawable background = TextDrawable.builder().buildRound(" ", backgroundColor); RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(context.getResources().getDrawable(resourceId)); foreground.setScaleType(ImageView.ScaleType.CENTER); diff --git a/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java b/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java index ad1f758059..9cd398e3e9 100644 --- a/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java +++ b/src/org/thoughtcrime/securesms/contacts/avatars/TransparentContactPhoto.java @@ -10,7 +10,7 @@ public class TransparentContactPhoto implements ContactPhoto { TransparentContactPhoto() {} @Override - public Drawable asDrawable(Context context) { + public Drawable asDrawable(Context context, int background) { return RoundedDrawable.fromDrawable(context.getResources().getDrawable(android.R.color.transparent)); } } diff --git a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java index f4ba0dd551..33d422b7b2 100644 --- a/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java +++ b/src/org/thoughtcrime/securesms/database/RecipientPreferenceDatabase.java @@ -29,6 +29,7 @@ public class RecipientPreferenceDatabase extends Database { private static final String NOTIFICATION = "notification"; private static final String VIBRATE = "vibrate"; private static final String MUTE_UNTIL = "mute_until"; + private static final String COLOR = "color"; public enum VibrateState { DEFAULT(0), ENABLED(1), DISABLED(2); @@ -55,7 +56,8 @@ public class RecipientPreferenceDatabase extends Database { BLOCK + " INTEGER DEFAULT 0," + NOTIFICATION + " TEXT DEFAULT NULL, " + VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " + - MUTE_UNTIL + " INTEGER DEFAULT 0);"; + MUTE_UNTIL + " INTEGER DEFAULT 0, " + + COLOR + " INTEGER DEFAULT -1);"; public RecipientPreferenceDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); @@ -87,13 +89,16 @@ public class RecipientPreferenceDatabase extends Database { String notification = cursor.getString(cursor.getColumnIndexOrThrow(NOTIFICATION)); int vibrateState = cursor.getInt(cursor.getColumnIndexOrThrow(VIBRATE)); long muteUntil = cursor.getLong(cursor.getColumnIndexOrThrow(MUTE_UNTIL)); + int color = cursor.getInt(cursor.getColumnIndexOrThrow(COLOR)); Uri notificationUri = notification == null ? null : Uri.parse(notification); Log.w(TAG, "Muted until: " + muteUntil); return Optional.of(new RecipientsPreferences(blocked, muteUntil, VibrateState.fromId(vibrateState), - notificationUri)); + notificationUri, + color == -1 ? Optional.absent() : + Optional.of(color))); } return Optional.absent(); @@ -102,6 +107,12 @@ public class RecipientPreferenceDatabase extends Database { } } + public void setColor(Recipients recipients, int color) { + ContentValues values = new ContentValues(); + values.put(COLOR, color); + updateOrInsert(recipients, values); + } + public void setBlocked(Recipients recipients, boolean blocked) { ContentValues values = new ContentValues(); values.put(BLOCK, blocked ? 1 : 0); @@ -147,16 +158,24 @@ public class RecipientPreferenceDatabase extends Database { } public static class RecipientsPreferences { - private final boolean blocked; - private final long muteUntil; - private final VibrateState vibrateState; - private final Uri notification; - - public RecipientsPreferences(boolean blocked, long muteUntil, VibrateState vibrateState, Uri notification) { + private final boolean blocked; + private final long muteUntil; + private final VibrateState vibrateState; + private final Uri notification; + private final Optional color; + + public RecipientsPreferences(boolean blocked, long muteUntil, VibrateState vibrateState, + Uri notification, Optional color) + { this.blocked = blocked; this.muteUntil = muteUntil; this.vibrateState = vibrateState; this.notification = notification; + this.color = color; + } + + public Optional getColor() { + return color; } public boolean isBlocked() { diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index fe5950a359..a35bf54d6c 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -46,6 +46,7 @@ import android.util.Log; import org.thoughtcrime.securesms.ConversationActivity; import org.thoughtcrime.securesms.ConversationListActivity; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsSmsDatabase; @@ -192,8 +193,10 @@ public class MessageNotifier { List notifications = notificationState.getNotifications(); NotificationCompat.Builder builder = new NotificationCompat.Builder(context); Recipient recipient = notifications.get(0).getIndividualRecipient(); - Drawable recipientPhoto = recipient.getContactPhoto().asDrawable(context); + Recipients recipients = notifications.get(0).getRecipients(); int largeIconTargetSize = context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size); + Drawable recipientPhoto = recipient.getContactPhoto().asDrawable(context, recipients == null ? ContactColors.UNKNOWN_COLOR : + recipients.getColor().or(ContactColors.UNKNOWN_COLOR)); if (recipientPhoto != null) { Bitmap recipientPhotoBitmap = BitmapUtil.createFromDrawable(recipientPhoto, largeIconTargetSize, largeIconTargetSize); diff --git a/src/org/thoughtcrime/securesms/recipients/Recipient.java b/src/org/thoughtcrime/securesms/recipients/Recipient.java index 2fadc030bd..a56cc81341 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipient.java @@ -18,6 +18,7 @@ package org.thoughtcrime.securesms.recipients; import android.net.Uri; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.util.Log; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; @@ -92,7 +93,7 @@ public class Recipient { return this.contactUri; } - public synchronized String getName() { + public synchronized @Nullable String getName() { return this.name; } diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java index 893860f944..1d1132b68c 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientProvider.java @@ -178,12 +178,14 @@ public class RecipientProvider { } public static class RecipientDetails { - public final String name; - public final String number; - public final ContactPhoto avatar; - public final Uri contactUri; - - public RecipientDetails(String name, String number, Uri contactUri, ContactPhoto avatar) { + @Nullable public final String name; + @NonNull public final String number; + @NonNull public final ContactPhoto avatar; + @Nullable public final Uri contactUri; + + public RecipientDetails(@Nullable String name, @NonNull String number, + @Nullable Uri contactUri, @NonNull ContactPhoto avatar) + { this.name = name; this.number = number; this.avatar = avatar; diff --git a/src/org/thoughtcrime/securesms/recipients/Recipients.java b/src/org/thoughtcrime/securesms/recipients/Recipients.java index fec47e1cd0..84ad760d43 100644 --- a/src/org/thoughtcrime/securesms/recipients/Recipients.java +++ b/src/org/thoughtcrime/securesms/recipients/Recipients.java @@ -22,6 +22,7 @@ import android.support.annotation.Nullable; import android.util.Log; import android.util.Patterns; +import org.thoughtcrime.securesms.contacts.avatars.ContactColors; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.ContactPhotoFactory; import org.thoughtcrime.securesms.database.RecipientPreferenceDatabase.RecipientsPreferences; @@ -32,6 +33,7 @@ import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.ListenableFutureTask; import org.thoughtcrime.securesms.util.NumberUtil; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.libaxolotl.util.guava.Optional; import java.util.Arrays; import java.util.Collections; @@ -49,10 +51,11 @@ public class Recipients implements Iterable, RecipientModifiedListene private final Set listeners = Collections.newSetFromMap(new WeakHashMap()); private final List recipients; - private Uri ringtone = null; - private long mutedUntil = 0; - private boolean blocked = false; - private VibrateState vibrate = VibrateState.DEFAULT; + private Uri ringtone = null; + private long mutedUntil = 0; + private boolean blocked = false; + private VibrateState vibrate = VibrateState.DEFAULT; + private Optional color = Optional.absent(); Recipients() { this(new LinkedList(), (RecipientsPreferences)null); @@ -66,6 +69,7 @@ public class Recipients implements Iterable, RecipientModifiedListene mutedUntil = preferences.getMuteUntil(); vibrate = preferences.getVibrateState(); blocked = preferences.isBlocked(); + color = preferences.getColor(); } } @@ -84,6 +88,7 @@ public class Recipients implements Iterable, RecipientModifiedListene mutedUntil = result.getMuteUntil(); vibrate = result.getVibrateState(); blocked = result.isBlocked(); + color = result.getColor(); localListeners = new HashSet<>(listeners); } @@ -101,6 +106,21 @@ public class Recipients implements Iterable, RecipientModifiedListene }); } + public synchronized Optional getColor() { + if (color.isPresent()) return color; + else if (isGroupRecipient()) return Optional.absent(); + else if (recipients.get(0).getName() == null) return Optional.absent(); + else return Optional.of(ContactColors.generateFor(recipients.get(0).getName())); + } + + public void setColor(Optional color) { + synchronized (this) { + this.color = color; + } + + notifyListeners(); + } + public synchronized @Nullable Uri getRingtone() { return ringtone; }