Separate avatar colors from chat colors.

This commit is contained in:
Greyson Parrelli 2021-05-25 22:44:19 -04:00
parent bcc5d485ab
commit 6342a45b4e
29 changed files with 364 additions and 133 deletions

View file

@ -23,13 +23,11 @@ import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
@ -100,9 +98,9 @@ public final class AvatarImageView extends AppCompatImageView {
typedArray.recycle();
}
outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
outlinePaint = ThemeUtil.isDarkTheme(context) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
unknownRecipientDrawable = new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20).asDrawable(getContext(), ChatColorsPalette.UNKNOWN_CONTACT, inverted);
unknownRecipientDrawable = new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20).asDrawable(context, AvatarColor.UNKNOWN.colorInt(), inverted);
blurred = false;
chatColors = null;
}
@ -213,7 +211,7 @@ public final class AvatarImageView extends AppCompatImageView {
requestManager.clear(this);
if (fallbackPhotoProvider != null) {
setImageDrawable(fallbackPhotoProvider.getPhotoForRecipientWithoutName()
.asDrawable(getContext(), ChatColorsPalette.Bubbles.STEEL, inverted));
.asDrawable(getContext(), AvatarColor.UNKNOWN.colorInt(), inverted));
} else {
setImageDrawable(unknownRecipientDrawable);
}
@ -246,11 +244,11 @@ public final class AvatarImageView extends AppCompatImageView {
public void setImageBytesForGroup(@Nullable byte[] avatarBytes,
@Nullable Recipient.FallbackPhotoProvider fallbackPhotoProvider,
@NonNull ChatColors color)
@NonNull AvatarColor color)
{
Drawable fallback = Util.firstNonNull(fallbackPhotoProvider, Recipient.DEFAULT_FALLBACK_PHOTO_PROVIDER)
.getPhotoForGroup()
.asDrawable(getContext(), color);
.asDrawable(getContext(), color.colorInt());
GlideApp.with(this)
.load(avatarBytes)

View file

@ -3,13 +3,11 @@ package org.thoughtcrime.securesms.contacts.avatars;
import android.content.Context;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
public interface FallbackContactPhoto {
Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors);
Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted);
Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted);
Drawable asCallCard(@NonNull Context context);
public Drawable asDrawable(Context context, int color);
public Drawable asDrawable(Context context, int color, boolean inverted);
public Drawable asSmallDrawable(Context context, int color, boolean inverted);
public Drawable asCallCard(Context context);
}

View file

@ -7,9 +7,9 @@ import android.graphics.drawable.LayerDrawable;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.graphics.drawable.DrawableCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Objects;
@ -26,18 +26,18 @@ public final class FallbackPhoto20dp implements FallbackContactPhoto {
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors) {
return buildDrawable(context, chatColors);
public Drawable asDrawable(Context context, int color) {
return buildDrawable(context, color);
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return buildDrawable(context, chatColors);
public Drawable asDrawable(Context context, int color, boolean inverted) {
return buildDrawable(context, color);
}
@Override
public Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return buildDrawable(context, chatColors);
public Drawable asSmallDrawable(Context context, int color, boolean inverted) {
return buildDrawable(context, color);
}
@Override
@ -45,13 +45,15 @@ public final class FallbackPhoto20dp implements FallbackContactPhoto {
throw new UnsupportedOperationException();
}
private @NonNull Drawable buildDrawable(@NonNull Context context, @NonNull ChatColors backgroundColor) {
Drawable background = backgroundColor.asCircle();
private @NonNull Drawable buildDrawable(@NonNull Context context, int color) {
Drawable background = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, R.drawable.circle_tintable))).mutate();
Drawable foreground = AppCompatResources.getDrawable(context, drawable20dp);
Drawable gradient = AppCompatResources.getDrawable(context, R.drawable.avatar_gradient);
LayerDrawable drawable = new LayerDrawable(new Drawable[]{background, foreground, gradient});
int foregroundInset = ViewUtil.dpToPx(2);
DrawableCompat.setTint(background, color);
drawable.setLayerInset(1, foregroundInset, foregroundInset, foregroundInset, foregroundInset);
return drawable;

View file

@ -10,7 +10,6 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.graphics.drawable.DrawableCompat;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Objects;
@ -18,40 +17,42 @@ import java.util.Objects;
public final class FallbackPhoto80dp implements FallbackContactPhoto {
@DrawableRes private final int drawable80dp;
private final ChatColors backgroundColor;
private final int backgroundColor;
public FallbackPhoto80dp(@DrawableRes int drawable80dp, @NonNull ChatColors backgroundColor) {
public FallbackPhoto80dp(@DrawableRes int drawable80dp, int backgroundColor) {
this.drawable80dp = drawable80dp;
this.backgroundColor = backgroundColor;
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors) {
public Drawable asDrawable(Context context, int color) {
return buildDrawable(context);
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
public Drawable asDrawable(Context context, int color, boolean inverted) {
return buildDrawable(context);
}
@Override
public Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
public Drawable asSmallDrawable(Context context, int color, boolean inverted) {
throw new UnsupportedOperationException();
}
@Override
public Drawable asCallCard(@NonNull Context context) {
public Drawable asCallCard(Context context) {
throw new UnsupportedOperationException();
}
private @NonNull Drawable buildDrawable(@NonNull Context context) {
Drawable background = backgroundColor.asCircle();
Drawable background = DrawableCompat.wrap(Objects.requireNonNull(AppCompatResources.getDrawable(context, R.drawable.circle_tintable))).mutate();
Drawable foreground = AppCompatResources.getDrawable(context, drawable80dp);
Drawable gradient = AppCompatResources.getDrawable(context, R.drawable.avatar_gradient);
LayerDrawable drawable = new LayerDrawable(new Drawable[]{background, foreground, gradient});
int foregroundInset = ViewUtil.dpToPx(24);
DrawableCompat.setTint(background, backgroundColor);
drawable.setLayerInset(1, foregroundInset, foregroundInset, foregroundInset, foregroundInset);
return drawable;

View file

@ -15,7 +15,6 @@ import androidx.appcompat.content.res.AppCompatResources;
import com.amulyakhare.textdrawable.TextDrawable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -43,12 +42,12 @@ public class GeneratedContactPhoto implements FallbackContactPhoto {
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors) {
return asDrawable(context, chatColors, false);
public Drawable asDrawable(Context context, int color) {
return asDrawable(context, color,false);
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
public Drawable asDrawable(Context context, int color, boolean inverted) {
int targetSize = this.targetSize != -1
? this.targetSize
: context.getResources().getDimensionPixelSize(R.dimen.contact_photo_target_size);
@ -56,36 +55,34 @@ public class GeneratedContactPhoto implements FallbackContactPhoto {
String character = getAbbreviation(name);
if (!TextUtils.isEmpty(character)) {
Drawable background = chatColors.asCircle();
Drawable base = TextDrawable.builder()
.beginConfig()
.width(targetSize)
.height(targetSize)
.useFont(TYPEFACE)
.fontSize(fontSize)
.textColor(inverted ? chatColors.asSingleColor() : Color.WHITE)
.textColor(inverted ? color : Color.WHITE)
.endConfig()
.buildRound(character, inverted ? Color.WHITE : Color.TRANSPARENT);
.buildRound(character, inverted ? Color.WHITE : color);
Drawable gradient = ContextUtil.requireDrawable(context, R.drawable.avatar_gradient);
return new LayerDrawable(new Drawable[] { background, base, gradient });
return new LayerDrawable(new Drawable[] { base, gradient });
}
return newFallbackDrawable(context, chatColors, inverted);
return newFallbackDrawable(context, color, inverted);
}
@Override
public Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return asDrawable(context, chatColors, inverted);
public Drawable asSmallDrawable(Context context, int color, boolean inverted) {
return asDrawable(context, color, inverted);
}
protected @DrawableRes int getFallbackResId() {
return fallbackResId;
}
protected Drawable newFallbackDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return new ResourceContactPhoto(fallbackResId).asDrawable(context, chatColors, inverted);
protected Drawable newFallbackDrawable(@NonNull Context context, int color, boolean inverted) {
return new ResourceContactPhoto(fallbackResId).asDrawable(context, color, inverted);
}
private @Nullable String getAbbreviation(String name) {

View file

@ -16,7 +16,6 @@ import com.amulyakhare.textdrawable.TextDrawable;
import com.makeramen.roundedimageview.RoundedDrawable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.util.ContextUtil;
public class ResourceContactPhoto implements FallbackContactPhoto {
@ -46,29 +45,29 @@ public class ResourceContactPhoto implements FallbackContactPhoto {
}
@Override
public @NonNull Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors) {
return asDrawable(context, chatColors, false);
public @NonNull Drawable asDrawable(@NonNull Context context, int color) {
return asDrawable(context, color, false);
}
@Override
public @NonNull Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return buildDrawable(context, resourceId, chatColors, inverted);
public @NonNull Drawable asDrawable(@NonNull Context context, int color, boolean inverted) {
return buildDrawable(context, resourceId, color, inverted);
}
@Override
public @NonNull Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return buildDrawable(context, smallResourceId, chatColors, inverted);
public @NonNull Drawable asSmallDrawable(@NonNull Context context, int color, boolean inverted) {
return buildDrawable(context, smallResourceId, color, inverted);
}
private @NonNull Drawable buildDrawable(@NonNull Context context, int resourceId, @NonNull ChatColors chatColors, boolean inverted) {
Drawable background = chatColors.asCircle();
private @NonNull Drawable buildDrawable(@NonNull Context context, int resourceId, int color, boolean inverted) {
Drawable background = TextDrawable.builder().buildRound(" ", inverted ? Color.WHITE : color);
RoundedDrawable foreground = (RoundedDrawable) RoundedDrawable.fromDrawable(AppCompatResources.getDrawable(context, resourceId));
//noinspection ConstantConditions
foreground.setScaleType(scaleType);
if (inverted) {
foreground.setColorFilter(chatColors.asSingleColor(), PorterDuff.Mode.SRC_ATOP);
foreground.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
}
Drawable gradient = ContextUtil.requireDrawable(context, R.drawable.avatar_gradient);

View file

@ -3,35 +3,33 @@ package org.thoughtcrime.securesms.contacts.avatars;
import android.content.Context;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.makeramen.roundedimageview.RoundedDrawable;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
public class TransparentContactPhoto implements FallbackContactPhoto {
public TransparentContactPhoto() {}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors) {
return asDrawable(context, chatColors, false);
public Drawable asDrawable(Context context, int color) {
return asDrawable(context, color, false);
}
@Override
public Drawable asDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
public Drawable asDrawable(Context context, int color, boolean inverted) {
return RoundedDrawable.fromDrawable(context.getResources().getDrawable(android.R.color.transparent));
}
@Override
public Drawable asSmallDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return asDrawable(context, chatColors, inverted);
public Drawable asSmallDrawable(Context context, int color, boolean inverted) {
return asDrawable(context, color, inverted);
}
@Override
public Drawable asCallCard(@NonNull Context context) {
public Drawable asCallCard(Context context) {
return ContextCompat.getDrawable(context, R.drawable.ic_contact_picture_large);
}

View file

@ -1252,7 +1252,7 @@ public class ConversationActivity extends PassphraseRequiredActivity
GlideApp.with(this)
.asBitmap()
.load(recipient.getContactPhoto())
.error(recipient.getFallbackContactPhoto().asDrawable(this, recipient.getChatColors(), false))
.error(recipient.getFallbackContactPhoto().asDrawable(this, recipient.getAvatarColor().colorInt(), false))
.into(new CustomTarget<Bitmap>() {
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {

View file

@ -0,0 +1,153 @@
package org.thoughtcrime.securesms.conversation.colors;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* A serializable set of color constants that can be used for avatars.
*/
public enum AvatarColor {
C000("C000", 0xFFD00B0B),
C010("C010", 0xFFC72A0A),
C020("C020", 0xFFB34209),
C030("C030", 0xFF9C5711),
C040("C040", 0xFF866118),
C050("C050", 0xFF76681E),
C060("C060", 0xFF6C6C13),
C070("C070", 0xFF5E6E0C),
C080("C080", 0xFF507406),
C090("C090", 0xFF3D7406),
C100("C100", 0xFF2D7906),
C110("C110", 0xFF1A7906),
C120("C120", 0xFF067906),
C130("C130", 0xFF067919),
C140("C140", 0xFF06792D),
C150("C150", 0xFF067940),
C160("C160", 0xFF067953),
C170("C170", 0xFF067462),
C180("C180", 0xFF067474),
C190("C190", 0xFF077288),
C200("C200", 0xFF086DA0),
C210("C210", 0xFF0A69C7),
C220("C220", 0xFF0D59F2),
C230("C230", 0xFF3454F4),
C240("C240", 0xFF5151F6),
C250("C250", 0xFF6447F5),
C260("C260", 0xFF7A3DF5),
C270("C270", 0xFF8F2AF4),
C280("C280", 0xFFA20CED),
C290("C290", 0xFFAF0BD0),
C300("C300", 0xFFB80AB8),
C310("C310", 0xFFC20AA3),
C320("C320", 0xFFC70A88),
C330("C330", 0xFFCB0B6B),
C340("C340", 0xFFD00B4D),
C350("C350", 0xFFD00B2C),
CRIMSON("crimson", ChatColorsPalette.Bubbles.CRIMSON.asSingleColor()),
VERMILLION("vermillion", ChatColorsPalette.Bubbles.VERMILION.asSingleColor()),
BURLAP("burlap", ChatColorsPalette.Bubbles.BURLAP.asSingleColor()),
FOREST("forest", ChatColorsPalette.Bubbles.FOREST.asSingleColor()),
WINTERGREEN("wintergreen", ChatColorsPalette.Bubbles.WINTERGREEN.asSingleColor()),
TEAL("teal", ChatColorsPalette.Bubbles.TEAL.asSingleColor()),
BLUE("blue", ChatColorsPalette.Bubbles.BLUE.asSingleColor()),
INDIGO("indigo", ChatColorsPalette.Bubbles.INDIGO.asSingleColor()),
VIOLET("violet", ChatColorsPalette.Bubbles.VIOLET.asSingleColor()),
PLUM("plum", ChatColorsPalette.Bubbles.PLUM.asSingleColor()),
TAUPE("taupe", ChatColorsPalette.Bubbles.TAUPE.asSingleColor()),
STEEL("steel", ChatColorsPalette.Bubbles.STEEL.asSingleColor()),
ULTRAMARINE("ultramarine", ChatColorsPalette.Bubbles.ULTRAMARINE.asSingleColor()),
UNKNOWN("unknown", ChatColorsPalette.Bubbles.STEEL.asSingleColor());
/** Fast map of name to enum, while also giving us a location to map old colors to new ones. */
private static final Map<String, AvatarColor> NAME_MAP = new HashMap<>();
static {
for (AvatarColor color : AvatarColor.values()) {
NAME_MAP.put(color.serialize(), color);
}
NAME_MAP.put("red", CRIMSON);
NAME_MAP.put("orange", VERMILLION);
NAME_MAP.put("deep_orange", VERMILLION);
NAME_MAP.put("brown", BURLAP);
NAME_MAP.put("green", FOREST);
NAME_MAP.put("light_green", WINTERGREEN);
NAME_MAP.put("teal", TEAL);
NAME_MAP.put("blue", BLUE);
NAME_MAP.put("indigo", INDIGO);
NAME_MAP.put("purple", VIOLET);
NAME_MAP.put("deep_purple", VIOLET);
NAME_MAP.put("pink", PLUM);
NAME_MAP.put("blue_grey", TAUPE);
NAME_MAP.put("grey", STEEL);
NAME_MAP.put("ultramarine", ULTRAMARINE);
}
/** Colors that can be assigned via {@link #random()}. */
private static final AvatarColor[] RANDOM_OPTIONS = new AvatarColor[] {
C000,
C010,
C020,
C030,
C040,
C050,
C060,
C070,
C080,
C090,
C100,
C110,
C120,
C130,
C140,
C150,
C160,
C170,
C180,
C190,
C200,
C210,
C220,
C230,
C240,
C250,
C260,
C270,
C280,
C290,
C300,
C310,
C320,
C330,
C340,
C350,
};
private final String name;
private final int color;
AvatarColor(@NonNull String name, @ColorInt int color) {
this.name = name;
this.color = color;
}
public @ColorInt int colorInt() {
return color;
}
public static @NonNull AvatarColor random() {
int position = (int) Math.floor(Math.random() * RANDOM_OPTIONS.length);
return RANDOM_OPTIONS[position];
}
public @NonNull String serialize() {
return name;
}
public static @NonNull AvatarColor deserialize(@NonNull String name) {
return Objects.requireNonNull(NAME_MAP.getOrDefault(name, C000));
}
}

View file

@ -8,8 +8,8 @@ import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
import com.google.common.base.Objects
import org.signal.core.util.ColorUtil
import org.thoughtcrime.securesms.components.RotatableGradientDrawable
import org.thoughtcrime.securesms.database.model.databaseprotos.ChatColor
import org.thoughtcrime.securesms.util.customizeOnDraw
@ -55,7 +55,7 @@ class ChatColors private constructor(
val start = linearGradient.colors.first()
val end = linearGradient.colors.last()
return ColorUtils.blendARGB(start, end, 0.5f)
return ColorUtil.blendARGB(start, end, 0.5f)
}
throw AssertionError()

View file

@ -23,7 +23,7 @@ object ChatColorsPalette {
// region Solids
@JvmField
val CRIMSON = ChatColors.forColor(ChatColors.Id.BuiltIn, 0xFFCF16E3.toInt())
val CRIMSON = ChatColors.forColor(ChatColors.Id.BuiltIn, 0xFFCF163E.toInt())
@JvmField
val VERMILION = ChatColors.forColor(ChatColors.Id.BuiltIn, 0xFFC73F0A.toInt())

View file

@ -24,6 +24,7 @@ import org.signal.zkgroup.groups.GroupMasterKey;
import org.signal.zkgroup.profiles.ProfileKey;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper;
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
@ -112,7 +113,7 @@ public class RecipientDatabase extends Database {
private static final String CALL_VIBRATE = "call_vibrate";
private static final String NOTIFICATION_CHANNEL = "notification_channel";
private static final String MUTE_UNTIL = "mute_until";
//private static final String COLOR = "color";
private static final String AVATAR_COLOR = "color";
private static final String SEEN_INVITE_REMINDER = "seen_invite_reminder";
private static final String DEFAULT_SUBSCRIPTION_ID = "default_subscription_id";
private static final String MESSAGE_EXPIRATION_TIME = "message_expiration_time";
@ -164,7 +165,7 @@ public class RecipientDatabase extends Database {
private static final String[] RECIPIENT_PROJECTION = new String[] {
ID, UUID, USERNAME, PHONE, EMAIL, GROUP_ID, GROUP_TYPE,
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
BLOCKED, MESSAGE_RINGTONE, CALL_RINGTONE, MESSAGE_VIBRATE, CALL_VIBRATE, MUTE_UNTIL, AVATAR_COLOR, SEEN_INVITE_REMINDER, DEFAULT_SUBSCRIPTION_ID, MESSAGE_EXPIRATION_TIME, REGISTERED,
PROFILE_KEY, PROFILE_KEY_CREDENTIAL,
SYSTEM_JOINED_NAME, SYSTEM_GIVEN_NAME, SYSTEM_FAMILY_NAME, SYSTEM_PHOTO_URI, SYSTEM_PHONE_LABEL, SYSTEM_PHONE_TYPE, SYSTEM_CONTACT_URI,
PROFILE_GIVEN_NAME, PROFILE_FAMILY_NAME, SIGNAL_PROFILE_AVATAR, PROFILE_SHARING, LAST_PROFILE_FETCH,
@ -326,6 +327,7 @@ public class RecipientDatabase extends Database {
CALL_VIBRATE + " INTEGER DEFAULT " + VibrateState.DEFAULT.getId() + ", " +
NOTIFICATION_CHANNEL + " TEXT DEFAULT NULL, " +
MUTE_UNTIL + " INTEGER DEFAULT 0, " +
AVATAR_COLOR + " TEXT DEFAULT NULL, " +
SEEN_INVITE_REMINDER + " INTEGER DEFAULT " + InsightsBannerTier.NO_TIER.getId() + ", " +
DEFAULT_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " +
MESSAGE_EXPIRATION_TIME + " INTEGER DEFAULT 0, " +
@ -559,6 +561,7 @@ public class RecipientDatabase extends Database {
values.put(UUID, uuid.toString().toLowerCase());
values.put(REGISTERED, RegisteredState.REGISTERED.getId());
values.put(STORAGE_SERVICE_ID, Base64.encodeBytes(StorageSyncHelper.generateKey()));
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
}
return values;
@ -589,6 +592,7 @@ public class RecipientDatabase extends Database {
} else {
ContentValues values = new ContentValues();
values.put(GROUP_ID, groupId.toString());
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
long id = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
@ -866,7 +870,7 @@ public class RecipientDatabase extends Database {
public void applyStorageSyncGroupV1Insert(@NonNull SignalGroupV1Record insert) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
long id = db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert));
long id = db.insertOrThrow(TABLE_NAME, null, getValuesForStorageGroupV1(insert, true));
RecipientId recipientId = RecipientId.from(id);
DatabaseFactory.getThreadDatabase(context).applyStorageSyncUpdate(recipientId, insert);
@ -877,7 +881,7 @@ public class RecipientDatabase extends Database {
public void applyStorageSyncGroupV1Update(@NonNull StorageRecordUpdate<SignalGroupV1Record> update) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = getValuesForStorageGroupV1(update.getNew());
ContentValues values = getValuesForStorageGroupV1(update.getNew(), false);
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_ID + " = ?", new String[]{Base64.encodeBytes(update.getOld().getId().getRaw())});
if (updateCount < 1) {
@ -896,7 +900,7 @@ public class RecipientDatabase extends Database {
GroupMasterKey masterKey = insert.getMasterKeyOrThrow();
GroupId.V2 groupId = GroupId.v2(masterKey);
ContentValues values = getValuesForStorageGroupV2(insert);
ContentValues values = getValuesForStorageGroupV2(insert, true);
long id = db.insertOrThrow(TABLE_NAME, null, values);
Recipient recipient = Recipient.externalGroupExact(context, groupId);
@ -919,7 +923,7 @@ public class RecipientDatabase extends Database {
public void applyStorageSyncGroupV2Update(@NonNull StorageRecordUpdate<SignalGroupV2Record> update) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = getValuesForStorageGroupV2(update.getNew());
ContentValues values = getValuesForStorageGroupV2(update.getNew(), false);
int updateCount = db.update(TABLE_NAME, values, STORAGE_SERVICE_ID + " = ?", new String[]{Base64.encodeBytes(update.getOld().getId().getRaw())});
if (updateCount < 1) {
@ -1037,10 +1041,14 @@ public class RecipientDatabase extends Database {
values.putNull(STORAGE_PROTO);
}
if (isInsert) {
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
}
return values;
}
private static @NonNull ContentValues getValuesForStorageGroupV1(@NonNull SignalGroupV1Record groupV1) {
private static @NonNull ContentValues getValuesForStorageGroupV1(@NonNull SignalGroupV1Record groupV1, boolean isInsert) {
ContentValues values = new ContentValues();
values.put(GROUP_ID, GroupId.v1orThrow(groupV1.getGroupId()).toString());
values.put(GROUP_TYPE, GroupType.SIGNAL_V1.getId());
@ -1055,10 +1063,14 @@ public class RecipientDatabase extends Database {
values.putNull(STORAGE_PROTO);
}
if (isInsert) {
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
}
return values;
}
private static @NonNull ContentValues getValuesForStorageGroupV2(@NonNull SignalGroupV2Record groupV2) {
private static @NonNull ContentValues getValuesForStorageGroupV2(@NonNull SignalGroupV2Record groupV2, boolean isInsert) {
ContentValues values = new ContentValues();
values.put(GROUP_ID, GroupId.v2(groupV2.getMasterKeyOrThrow()).toString());
values.put(GROUP_TYPE, GroupType.SIGNAL_V2.getId());
@ -1073,6 +1085,10 @@ public class RecipientDatabase extends Database {
values.putNull(STORAGE_PROTO);
}
if (isInsert) {
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
}
return values;
}
@ -1198,6 +1214,7 @@ public class RecipientDatabase extends Database {
byte[] wallpaper = CursorUtil.requireBlob(cursor, WALLPAPER);
byte[] serializedChatColors = CursorUtil.requireBlob(cursor, CHAT_COLORS);
long customChatColorsId = CursorUtil.requireLong(cursor, CUSTOM_CHAT_COLORS_ID);
String serializedAvatarColor = CursorUtil.requireString(cursor, AVATAR_COLOR);
String about = CursorUtil.requireString(cursor, ABOUT);
String aboutEmoji = CursorUtil.requireString(cursor, ABOUT_EMOJI);
boolean hasGroupsInCommon = CursorUtil.requireBoolean(cursor, GROUPS_IN_COMMON);
@ -1288,6 +1305,7 @@ public class RecipientDatabase extends Database {
MentionSetting.fromId(mentionSettingId),
chatWallpaper,
chatColors,
AvatarColor.deserialize(serializedAvatarColor),
about,
aboutEmoji,
getSyncExtras(cursor),
@ -2838,6 +2856,7 @@ public class RecipientDatabase extends Database {
} else {
ContentValues values = new ContentValues();
values.put(column, value);
values.put(AVATAR_COLOR, AvatarColor.random().serialize());
long id = databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values);
@ -2883,6 +2902,7 @@ public class RecipientDatabase extends Database {
uuidValues.put(NOTIFICATION_CHANNEL, uuidSettings.getNotificationChannel() != null ? uuidSettings.getNotificationChannel() : e164Settings.getNotificationChannel());
uuidValues.put(MUTE_UNTIL, uuidSettings.getMuteUntil() > 0 ? uuidSettings.getMuteUntil() : e164Settings.getMuteUntil());
uuidValues.put(CHAT_COLORS, Optional.fromNullable(uuidSettings.getChatColors()).or(Optional.fromNullable(e164Settings.getChatColors())).transform(colors -> colors.serialize().toByteArray()).orNull());
uuidValues.put(AVATAR_COLOR, uuidSettings.getAvatarColor().serialize());
uuidValues.put(CUSTOM_CHAT_COLORS_ID, Optional.fromNullable(uuidSettings.getChatColors()).or(Optional.fromNullable(e164Settings.getChatColors())).transform(colors -> colors.getId().getLongValue()).orNull());
uuidValues.put(SEEN_INVITE_REMINDER, e164Settings.getInsightsBannerTier().getId());
uuidValues.put(DEFAULT_SUBSCRIPTION_ID, e164Settings.getDefaultSubscriptionId().or(-1));
@ -3122,6 +3142,7 @@ public class RecipientDatabase extends Database {
private final MentionSetting mentionSetting;
private final ChatWallpaper wallpaper;
private final ChatColors chatColors;
private final AvatarColor avatarColor;
private final String about;
private final String aboutEmoji;
private final SyncExtras syncExtras;
@ -3165,6 +3186,7 @@ public class RecipientDatabase extends Database {
@NonNull MentionSetting mentionSetting,
@Nullable ChatWallpaper wallpaper,
@Nullable ChatColors chatColors,
@NonNull AvatarColor avatarColor,
@Nullable String about,
@Nullable String aboutEmoji,
@NonNull SyncExtras syncExtras,
@ -3210,6 +3232,7 @@ public class RecipientDatabase extends Database {
this.mentionSetting = mentionSetting;
this.wallpaper = wallpaper;
this.chatColors = chatColors;
this.avatarColor = avatarColor;
this.about = about;
this.aboutEmoji = aboutEmoji;
this.syncExtras = syncExtras;
@ -3369,6 +3392,10 @@ public class RecipientDatabase extends Database {
return chatColors;
}
public @NonNull AvatarColor getAvatarColor() {
return avatarColor;
}
public @Nullable String getAbout() {
return about;
}

View file

@ -24,6 +24,7 @@ import net.sqlcipher.database.SQLiteOpenHelper;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColorsLegacy;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsMapper;
import org.thoughtcrime.securesms.crypto.DatabaseSecret;
@ -188,8 +189,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
private static final int CLEAR_MMS_STORAGE_IDS = 98;
private static final int SERVER_GUID = 99;
private static final int CHAT_COLORS = 100;
private static final int AVATAR_COLORS = 101;
private static final int DATABASE_VERSION = 100;
private static final int DATABASE_VERSION = 101;
private static final String DATABASE_NAME = "signal.db";
private final Context context;
@ -1491,6 +1493,19 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper implements SignalDatab
}
}
if (oldVersion < AVATAR_COLORS) {
try (Cursor cursor = db.query("recipient", new String[] { "_id" }, "color IS NULL", null, null, null, null)) {
while (cursor.moveToNext()) {
long id = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));
ContentValues values = new ContentValues(1);
values.put("color", AvatarColor.random().serialize());
db.update("recipient", values, "_id = ?", new String[] { String.valueOf(id) });
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();

View file

@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupDescriptionDialog;
@ -88,7 +89,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
groupCancelButton.setOnClickListener(v -> dismiss());
avatar.setImageBytesForGroup(null, new FallbackPhotoProvider(), ChatColorsPalette.UNKNOWN_CONTACT);
avatar.setImageBytesForGroup(null, new FallbackPhotoProvider(), AvatarColor.UNKNOWN);
return view;
}
@ -130,7 +131,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
break;
}
avatar.setImageBytesForGroup(details.getAvatarBytes(), new FallbackPhotoProvider(), ChatColorsPalette.UNKNOWN_CONTACT);
avatar.setImageBytesForGroup(details.getAvatarBytes(), new FallbackPhotoProvider(), AvatarColor.UNKNOWN);
groupCancelButton.setVisibility(View.VISIBLE);
});

View file

@ -39,8 +39,7 @@ import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
@ -238,7 +237,7 @@ public class ManageGroupFragment extends LoggingFragment {
viewModel.getMemberCountSummary().observe(getViewLifecycleOwner(), memberCountUnderAvatar::setText);
viewModel.getFullMemberCountSummary().observe(getViewLifecycleOwner(), memberCountAboveList::setText);
viewModel.getGroupRecipient().observe(getViewLifecycleOwner(), groupRecipient -> {
avatar.setFallbackPhotoProvider(new FallbackPhotoProvider(groupRecipient.getChatColors()));
avatar.setFallbackPhotoProvider(new FallbackPhotoProvider(groupRecipient.getAvatarColor()));
avatar.setRecipient(groupRecipient);
avatar.setOnClickListener(v -> {
FragmentActivity activity = requireActivity();
@ -508,15 +507,15 @@ public class ManageGroupFragment extends LoggingFragment {
private final class FallbackPhotoProvider extends Recipient.FallbackPhotoProvider {
private final ChatColors groupColors;
private final AvatarColor groupColors;
private FallbackPhotoProvider(@NonNull ChatColors groupColors) {
private FallbackPhotoProvider(@NonNull AvatarColor groupColors) {
this.groupColors = groupColors;
}
@Override
public @NonNull FallbackContactPhoto getPhotoForGroup() {
return new FallbackPhoto80dp(R.drawable.ic_group_80, groupColors);
return new FallbackPhoto80dp(R.drawable.ic_group_80, groupColors.colorInt());
}
};
}

View file

@ -67,10 +67,9 @@ public class InsightsRepository implements InsightsDashboardViewModel.Repository
SimpleTask.run(() -> {
Recipient self = Recipient.self().resolve();
String name = Optional.fromNullable(self.getDisplayName(context)).or("");
ChatColors fallbackColor = self.getChatColors();
return new InsightsUserAvatar(new ProfileContactPhoto(self, self.getProfileAvatar()),
fallbackColor,
self.getAvatarColor(),
new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40));
}, avatarConsumer::accept);
}

View file

@ -10,22 +10,22 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.mms.GlideApp;
class InsightsUserAvatar {
private final ProfileContactPhoto profileContactPhoto;
private final ChatColors fallbackColor;
private final AvatarColor fallbackColor;
private final FallbackContactPhoto fallbackContactPhoto;
InsightsUserAvatar(@NonNull ProfileContactPhoto profileContactPhoto, @NonNull ChatColors fallbackColor, @NonNull FallbackContactPhoto fallbackContactPhoto) {
InsightsUserAvatar(@NonNull ProfileContactPhoto profileContactPhoto, @NonNull AvatarColor fallbackColor, @NonNull FallbackContactPhoto fallbackContactPhoto) {
this.profileContactPhoto = profileContactPhoto;
this.fallbackColor = fallbackColor;
this.fallbackContactPhoto = fallbackContactPhoto;
}
private Drawable fallbackDrawable(@NonNull Context context) {
return fallbackContactPhoto.asDrawable(context, fallbackColor);
return fallbackContactPhoto.asDrawable(context, fallbackColor.colorInt());
}
void load(ImageView into) {

View file

@ -27,12 +27,11 @@ import com.bumptech.glide.load.resource.bitmap.CircleCrop;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
@ -98,7 +97,7 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
} else {
setContentTitle(context.getString(R.string.SingleRecipientNotificationBuilder_signal));
setLargeIcon(new GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, ChatColorsPalette.UNKNOWN_CONTACT));
setLargeIcon(new GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, AvatarColor.UNKNOWN.colorInt()));
}
setShortcutId(ConversationUtil.getShortcutId(recipient));
@ -124,10 +123,10 @@ public class SingleRecipientNotificationBuilder extends AbstractNotificationBuil
context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_height))
.get();
} catch (InterruptedException | ExecutionException e) {
return fallbackContactPhoto.asDrawable(context, recipient.getChatColors());
return fallbackContactPhoto.asDrawable(context, recipient.getAvatarColor().colorInt());
}
} else {
return fallbackContactPhoto.asDrawable(context, recipient.getChatColors());
return fallbackContactPhoto.asDrawable(context, recipient.getAvatarColor().colorInt());
}
}

View file

@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.contacts.TurnOffContactJoinedNotificationsActivity
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto
import org.thoughtcrime.securesms.conversation.ConversationIntents
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette
import org.thoughtcrime.securesms.conversation.colors.AvatarColor
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.notifications.DeleteNotificationReceiver
import org.thoughtcrime.securesms.notifications.MarkReadReceiver
@ -52,7 +52,7 @@ data class NotificationConversation(
return if (SignalStore.settings().messageNotificationsPrivacy.isDisplayContact) {
recipient.getContactDrawable(context)
} else {
GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, ChatColorsPalette.UNKNOWN_CONTACT)
GeneratedContactPhoto("Unknown", R.drawable.ic_profile_outline_40).asDrawable(context, AvatarColor.UNKNOWN.colorInt())
}
}

View file

@ -56,12 +56,12 @@ fun Recipient.getContactDrawable(context: Context): Drawable? {
)
.get()
} catch (e: InterruptedException) {
fallbackContactPhoto.asDrawable(context, chatColors)
fallbackContactPhoto.asDrawable(context, avatarColor.colorInt())
} catch (e: ExecutionException) {
fallbackContactPhoto.asDrawable(context, chatColors)
fallbackContactPhoto.asDrawable(context, avatarColor.colorInt())
}
} else {
fallbackContactPhoto.asDrawable(context, chatColors)
fallbackContactPhoto.asDrawable(context, avatarColor.colorInt())
}
}

View file

@ -30,7 +30,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.LoggingFragment;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.mediasend.AvatarSelectionActivity;
import org.thoughtcrime.securesms.mediasend.AvatarSelectionBottomSheetDialogFragment;
@ -49,7 +49,6 @@ import java.io.IOException;
import java.io.InputStream;
import static android.app.Activity.RESULT_OK;
import static org.thoughtcrime.securesms.groups.v2.GroupDescriptionUtil.MAX_DESCRIPTION_LENGTH;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.EXCLUDE_SYSTEM;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.GROUP_ID;
import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.NEXT_BUTTON_TEXT;
@ -112,7 +111,7 @@ public class EditProfileFragment extends LoggingFragment {
if (data != null && data.getBooleanExtra("delete", false)) {
viewModel.setAvatar(null);
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_solid_white_24).asDrawable(requireActivity(), ChatColorsPalette.UNKNOWN_CONTACT));
avatar.setImageDrawable(new ResourceContactPhoto(R.drawable.ic_camera_solid_white_24).asDrawable(requireActivity(), AvatarColor.UNKNOWN.colorInt()));
return;
}

View file

@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto20dp;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.ViewUtil;
@ -123,8 +122,8 @@ public class ReviewBannerView extends LinearLayout {
}
@Override
protected Drawable newFallbackDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return new FallbackPhoto20dp(getFallbackResId()).asDrawable(context, chatColors, inverted);
protected Drawable newFallbackDrawable(@NonNull Context context, int color, boolean inverted) {
return new FallbackPhoto20dp(getFallbackResId()).asDrawable(context, color, inverted);
}
}
}

View file

@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.SystemContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.TransparentContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@ -107,6 +108,7 @@ public class Recipient {
private final MentionSetting mentionSetting;
private final ChatWallpaper wallpaper;
private final ChatColors chatColors;
private final AvatarColor avatarColor;
private final String about;
private final String aboutEmoji;
private final ProfileName systemProfileName;
@ -353,6 +355,7 @@ public class Recipient {
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
this.wallpaper = null;
this.chatColors = null;
this.avatarColor = AvatarColor.UNKNOWN;
this.about = null;
this.aboutEmoji = null;
this.systemProfileName = ProfileName.EMPTY;
@ -402,6 +405,7 @@ public class Recipient {
this.mentionSetting = details.mentionSetting;
this.wallpaper = details.wallpaper;
this.chatColors = details.chatColors;
this.avatarColor = details.avatarColor;
this.about = details.about;
this.aboutEmoji = details.aboutEmoji;
this.systemProfileName = details.systemProfileName;
@ -756,11 +760,11 @@ public class Recipient {
}
public @NonNull Drawable getFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asDrawable(context, getChatColors(), inverted);
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asDrawable(context, avatarColor.colorInt(), inverted);
}
public @NonNull Drawable getSmallFallbackContactPhotoDrawable(Context context, boolean inverted, @Nullable FallbackPhotoProvider fallbackPhotoProvider) {
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asSmallDrawable(context, getChatColors(), inverted);
return getFallbackContactPhoto(Util.firstNonNull(fallbackPhotoProvider, DEFAULT_FALLBACK_PHOTO_PROVIDER)).asSmallDrawable(context, avatarColor.colorInt(), inverted);
}
public @NonNull FallbackContactPhoto getFallbackContactPhoto() {
@ -927,6 +931,10 @@ public class Recipient {
}
}
public @NonNull AvatarColor getAvatarColor() {
return avatarColor;
}
public boolean isSystemContact() {
return contactUri != null;
}
@ -1114,6 +1122,7 @@ public class Recipient {
mentionSetting == other.mentionSetting &&
Objects.equals(wallpaper, other.wallpaper) &&
Objects.equals(chatColors, other.chatColors) &&
Objects.equals(avatarColor, other.avatarColor) &&
Objects.equals(about, other.about) &&
Objects.equals(aboutEmoji, other.aboutEmoji) &&
Objects.equals(extras, other.extras);

View file

@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.database.RecipientDatabase.InsightsBannerTier;
import org.thoughtcrime.securesms.database.RecipientDatabase.MentionSetting;
@ -67,6 +68,7 @@ public class RecipientDetails {
final MentionSetting mentionSetting;
final ChatWallpaper wallpaper;
final ChatColors chatColors;
final AvatarColor avatarColor;
final String about;
final String aboutEmoji;
final ProfileName systemProfileName;
@ -120,6 +122,7 @@ public class RecipientDetails {
this.mentionSetting = settings.getMentionSetting();
this.wallpaper = settings.getWallpaper();
this.chatColors = settings.getChatColors();
this.avatarColor = settings.getAvatarColor();
this.about = settings.getAbout();
this.aboutEmoji = settings.getAboutEmoji();
this.systemProfileName = settings.getSystemProfileName();
@ -172,6 +175,7 @@ public class RecipientDetails {
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
this.wallpaper = null;
this.chatColors = null;
this.avatarColor = AvatarColor.UNKNOWN;
this.about = null;
this.aboutEmoji = null;
this.systemProfileName = ProfileName.EMPTY;

View file

@ -34,7 +34,6 @@ import org.thoughtcrime.securesms.recipients.RecipientExporter;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.BottomSheetUtil;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
@ -140,7 +139,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
avatar.setFallbackPhotoProvider(new Recipient.FallbackPhotoProvider() {
@Override
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
return new FallbackPhoto80dp(R.drawable.ic_note_80, recipient.getChatColors());
return new FallbackPhoto80dp(R.drawable.ic_note_80, recipient.getAvatarColor().colorInt());
}
});
avatar.setAvatar(recipient);

View file

@ -32,7 +32,7 @@ import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
@ -309,16 +309,16 @@ public class ManageRecipientFragment extends LoggingFragment {
disappearingMessagesCard.setVisibility(recipient.isRegistered() ? View.VISIBLE : View.GONE);
addToAGroup.setVisibility(recipient.isRegistered() ? View.VISIBLE : View.GONE);
ChatColors recipientColor = recipient.getChatColors();
AvatarColor recipientColor = recipient.getAvatarColor();
avatar.setFallbackPhotoProvider(new Recipient.FallbackPhotoProvider() {
@Override
public @NonNull FallbackContactPhoto getPhotoForRecipientWithoutName() {
return new FallbackPhoto80dp(R.drawable.ic_profile_80, recipientColor);
return new FallbackPhoto80dp(R.drawable.ic_profile_80, recipientColor.colorInt());
}
@Override
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
return new FallbackPhoto80dp(R.drawable.ic_note_80, recipientColor);
return new FallbackPhoto80dp(R.drawable.ic_note_80, recipientColor.colorInt());
}
});
avatar.setAvatar(recipient);

View file

@ -4,7 +4,6 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
@ -21,13 +20,9 @@ import com.bumptech.glide.request.target.CustomViewTarget;
import com.bumptech.glide.request.transition.Transition;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.conversation.colors.ChatColorsPalette;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequest;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -174,8 +169,7 @@ public final class AvatarUtil {
private static Drawable getFallback(@NonNull Context context, @NonNull Recipient recipient) {
String name = Optional.fromNullable(recipient.getDisplayName(context)).or("");
ChatColors fallbackColor = recipient.getChatColors();
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40).asDrawable(context, fallbackColor);
return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40).asDrawable(context, recipient.getAvatarColor().colorInt());
}
}

View file

@ -23,9 +23,7 @@ import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.SystemContactPhoto;
import org.thoughtcrime.securesms.conversation.colors.ChatColors;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequest;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
@ -178,9 +176,9 @@ public final class ConversationShortcutPhoto implements Key {
photoSource = R.drawable.ic_profile_80;
}
FallbackContactPhoto photo = recipient.isSelf() || recipient.isGroup() ? new FallbackPhoto80dp(photoSource, recipient.getChatColors())
FallbackContactPhoto photo = recipient.isSelf() || recipient.isGroup() ? new FallbackPhoto80dp(photoSource, recipient.getAvatarColor().colorInt())
: new ShortcutGeneratedContactPhoto(recipient.getDisplayName(context), photoSource, ViewUtil.dpToPx(80), ViewUtil.dpToPx(28));
Bitmap toWrap = DrawableUtil.toBitmap(photo.asDrawable(context, recipient.getChatColors()), ViewUtil.dpToPx(80), ViewUtil.dpToPx(80));
Bitmap toWrap = DrawableUtil.toBitmap(photo.asDrawable(context, recipient.getAvatarColor().colorInt()), ViewUtil.dpToPx(80), ViewUtil.dpToPx(80));
Bitmap wrapped = DrawableUtil.wrapBitmapForShortcutInfo(toWrap);
toWrap.recycle();
@ -199,8 +197,8 @@ public final class ConversationShortcutPhoto implements Key {
}
@Override
protected Drawable newFallbackDrawable(@NonNull Context context, @NonNull ChatColors chatColors, boolean inverted) {
return new FallbackPhoto80dp(getFallbackResId(), chatColors).asDrawable(context, chatColors);
protected Drawable newFallbackDrawable(@NonNull Context context, int color, boolean inverted) {
return new FallbackPhoto80dp(getFallbackResId(), color).asDrawable(context, -1);
}
}
}

View file

@ -0,0 +1,43 @@
package org.signal.core.util;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
public final class ColorUtil {
private ColorUtil() {}
public static int blendARGB(@ColorInt int color1,
@ColorInt int color2,
@FloatRange(from = 0.0, to = 1.0) float ratio)
{
final float inverseRatio = 1 - ratio;
float a = alpha(color1) * inverseRatio + alpha(color2) * ratio;
float r = red(color1) * inverseRatio + red(color2) * ratio;
float g = green(color1) * inverseRatio + green(color2) * ratio;
float b = blue(color1) * inverseRatio + blue(color2) * ratio;
return argb((int) a, (int) r, (int) g, (int) b);
}
private static int alpha(int color) {
return color >>> 24;
}
private static int red(int color) {
return (color >> 16) & 0xFF;
}
private static int green(int color) {
return (color >> 8) & 0xFF;
}
private static int blue(int color) {
return color & 0xFF;
}
private static int argb(int alpha, int red, int green, int blue) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
}