Replace glyphs in group update messages.

This commit is contained in:
Sagar
2025-04-22 20:04:52 +05:30
committed by Cody Henthorne
parent 919f03522a
commit 9f40bfc645
15 changed files with 390 additions and 421 deletions

View File

@@ -262,7 +262,7 @@ fun MessageBackupsTypeBlock(
Text(
text = signalSymbolText(
text = stringResource(R.string.MessageBackupsTypeSelectionScreen__current_plan),
glyphStart = SignalSymbols.Glyph.CHECKMARK
glyphStart = SignalSymbols.Glyph.CHECK
),
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier

View File

@@ -687,7 +687,7 @@ private fun BackupCard(
Text(
text = signalSymbolText(
text = title,
glyphStart = if (backupState.isActive()) SignalSymbols.Glyph.CHECKMARK else null
glyphStart = if (backupState.isActive()) SignalSymbols.Glyph.CHECK else null
),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium

View File

@@ -72,6 +72,7 @@ import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.database.model.UpdateDescription;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.thoughtcrime.securesms.glide.GlideLiveDataTarget;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
@@ -588,9 +589,9 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
return emphasisAdded(context, context.getString(R.string.ThreadRecord_message_request), defaultTint);
}
} else if (thread.getRecipient().isBlocked() && thread.getRecipient().isGroup()) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_blocked_group), R.drawable.symbol_block_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_blocked_group), Glyph.BLOCK, defaultTint);
} else if (thread.getRecipient().isBlocked()) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_blocked), R.drawable.symbol_block_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_blocked), Glyph.BLOCK, defaultTint);
} else if (MessageTypes.isGroupUpdate(thread.getType())) {
if (thread.getRecipient().isPushV2Group()) {
if (thread.getMessageExtras() != null) {
@@ -599,14 +600,14 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
return emphasisAdded(context, MessageRecord.getGv2ChangeDescription(context, thread.getBody(), null), defaultTint);
}
} else {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_group_updated), R.drawable.ic_update_group_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_group_updated), Glyph.GROUP, defaultTint);
}
} else if (MessageTypes.isGroupQuit(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_left_the_group), R.drawable.ic_update_group_leave_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_left_the_group), Glyph.LEAVE, defaultTint);
} else if (MessageTypes.isKeyExchangeType(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.ConversationListItem_key_exchange_message), defaultTint);
} else if (MessageTypes.isChatSessionRefresh(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_chat_session_refreshed), R.drawable.ic_refresh_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_chat_session_refreshed), Glyph.REFRESH, defaultTint);
} else if (MessageTypes.isNoRemoteSessionType(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session), defaultTint);
} else if (MessageTypes.isEndSessionType(thread.getType())) {
@@ -614,22 +615,22 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
} else if (MessageTypes.isLegacyType(thread.getType())) {
return emphasisAdded(context, context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported), defaultTint);
} else if (thread.isScheduledMessage()) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_scheduled_message), R.drawable.symbol_calendar_compact_light_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_scheduled_message), Glyph.CALENDAR, defaultTint);
} else if (MessageTypes.isDraftMessageType(thread.getType())) {
String draftText = context.getString(R.string.ThreadRecord_draft);
return emphasisAdded(context, draftText + " " + thread.getBody(), defaultTint);
} else if (MessageTypes.isOutgoingAudioCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_outgoing_voice_call) : thread.getBody(), R.drawable.ic_update_audio_call_outgoing_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_outgoing_voice_call) : thread.getBody(), Glyph.PHONE, defaultTint);
} else if (MessageTypes.isOutgoingVideoCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_outgoing_video_call) : thread.getBody(), R.drawable.ic_update_video_call_outgoing_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_outgoing_video_call) : thread.getBody(), Glyph.VIDEO_CAMERA, defaultTint);
} else if (MessageTypes.isIncomingAudioCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_incoming_voice_call) : thread.getBody(), R.drawable.ic_update_audio_call_incoming_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_incoming_voice_call) : thread.getBody(), Glyph.PHONE, defaultTint);
} else if (MessageTypes.isIncomingVideoCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_incoming_video_call) : thread.getBody(), R.drawable.ic_update_video_call_incoming_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_incoming_video_call) : thread.getBody(), Glyph.VIDEO_CAMERA, defaultTint);
} else if (MessageTypes.isMissedAudioCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_missed_voice_call) : thread.getBody(), R.drawable.ic_update_audio_call_missed_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_missed_voice_call) : thread.getBody(), Glyph.PHONE, defaultTint);
} else if (MessageTypes.isMissedVideoCall(thread.getType())) {
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_missed_video_call) : thread.getBody(), R.drawable.ic_update_video_call_missed_16, defaultTint);
return emphasisAdded(context, StringUtil.isEmpty(thread.getBody()) ? context.getString(R.string.MessageRecord_missed_video_call) : thread.getBody(), Glyph.VIDEO_CAMERA, defaultTint);
} else if (MessageTypes.isGroupCall(thread.getType())) {
return emphasisAdded(context, MessageRecord.getGroupCallUpdateDescription(context, thread.getBody(), false), defaultTint);
} else if (MessageTypes.isJoinedType(thread.getType())) {
@@ -637,10 +638,10 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
} else if (MessageTypes.isExpirationTimerUpdate(thread.getType())) {
int seconds = (int) (thread.getExpiresIn() / 1000);
if (seconds <= 0) {
return emphasisAdded(context, context.getString(R.string.ThreadRecord_disappearing_messages_disabled), R.drawable.ic_update_timer_disabled_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_disappearing_messages_disabled), Glyph.TIMER_SLASH, defaultTint);
}
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time), R.drawable.ic_update_timer_16, defaultTint);
return emphasisAdded(context, context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time), Glyph.TIMER, defaultTint);
} else if (MessageTypes.isIdentityUpdate(thread.getType())) {
return emphasisAdded(recipientToStringAsync(thread.getRecipient().getId(), r -> {
if (r.isGroup()) {
@@ -772,11 +773,11 @@ public final class ConversationListItem extends ConstraintLayout implements Bind
}
private static @NonNull LiveData<SpannableString> emphasisAdded(@NonNull Context context, @NonNull String string, @ColorInt int defaultTint) {
return emphasisAdded(context, UpdateDescription.staticDescription(string, 0), defaultTint);
return emphasisAdded(context, UpdateDescription.staticDescription(string, null), defaultTint);
}
private static @NonNull LiveData<SpannableString> emphasisAdded(@NonNull Context context, @NonNull String string, @DrawableRes int iconResource, @ColorInt int defaultTint) {
return emphasisAdded(context, UpdateDescription.staticDescription(string, iconResource), defaultTint);
private static @NonNull LiveData<SpannableString> emphasisAdded(@NonNull Context context, @NonNull String string, @Nullable Glyph glyph, @ColorInt int defaultTint) {
return emphasisAdded(context, UpdateDescription.staticDescription(string, glyph), defaultTint);
}
private static @NonNull LiveData<SpannableString> emphasisAdded(@NonNull Context context, @NonNull UpdateDescription description, @ColorInt int defaultTint) {

View File

@@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
@@ -93,7 +94,7 @@ public class InMemoryMessageRecord extends MessageRecord {
@Override
public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context, @Nullable Consumer<RecipientId> recipientClickHandler) {
return UpdateDescription.staticDescription(context.getString(R.string.ConversationUpdateItem_hidden_contact_message_to_add_back),
R.drawable.symbol_info_compact_16);
Glyph.INFO);
}
@Override
@@ -122,7 +123,7 @@ public class InMemoryMessageRecord extends MessageRecord {
String update = context.getString(R.string.ConversationUpdateItem_the_disappearing_message_time_will_be_set_to_s_when_you_message_them,
ExpirationUtil.getExpirationDisplayValue(context, SignalStore.settings().getUniversalExpireTimer()));
return UpdateDescription.staticDescription(update, R.drawable.symbol_timer_compact_24);
return UpdateDescription.staticDescription(update, Glyph.TIMER);
}
@Override

View File

@@ -1,11 +1,6 @@
package org.thoughtcrime.securesms.database.model;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
@@ -18,12 +13,13 @@ import androidx.lifecycle.Transformations;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.fonts.SignalSymbols;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Weight;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.SpanUtil;
import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.util.List;
@@ -66,31 +62,25 @@ public final class LiveUpdateMessage {
}
private static @NonNull SpannableString toSpannable(@NonNull Context context, @NonNull UpdateDescription updateDescription, @NonNull Spannable string, @ColorInt int defaultTint, boolean adjustPosition) {
boolean isDarkTheme = ThemeUtil.isDarkTheme(context);
int drawableResource = updateDescription.getIconResource();
int tint = isDarkTheme ? updateDescription.getDarkTint() : updateDescription.getLightTint();
boolean isDarkTheme = ThemeUtil.isDarkTheme(context);
Glyph glyph = updateDescription.getGlyph();
int tint = isDarkTheme ? updateDescription.getDarkTint() : updateDescription.getLightTint();
if (tint == 0) {
tint = defaultTint;
}
if (drawableResource == 0) {
if (glyph == null) {
return new SpannableString(string);
} else {
Drawable drawable = ContextUtil.requireDrawable(context, drawableResource);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
drawable.setColorFilter(tint, PorterDuff.Mode.SRC_ATOP);
SpannableStringBuilder builder = new SpannableStringBuilder();
CharSequence glyphChar = SignalSymbols.getSpannedString(context, Weight.REGULAR, glyph, -1);
int insetTop = adjustPosition ? ViewUtil.dpToPx(2) : 0;
InsetDrawable insetDrawable = new InsetDrawable(drawable, 0, insetTop, 0, 0);
insetDrawable.setBounds(0, 0, drawable.getIntrinsicWidth(), insetDrawable.getIntrinsicHeight());
builder.append(glyphChar);
builder.append(" ");
builder.append(string);
Drawable spaceDrawable = new ColorDrawable(Color.TRANSPARENT);
spaceDrawable.setBounds(0, 0, ViewUtil.dpToPx(8), drawable.getIntrinsicHeight());
Spannable stringWithImage = new SpannableStringBuilder().append(SpanUtil.buildImageSpan(drawable)).append(SpanUtil.buildImageSpan(spaceDrawable)).append(string);
return new SpannableString(SpanUtil.color(tint, stringWithImage));
return new SpannableString(SpanUtil.color(tint, builder));
}
}
}

View File

@@ -29,6 +29,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.compose.ui.text.AnnotatedString;
import androidx.core.content.ContextCompat;
import com.annimon.stream.Stream;
@@ -54,6 +55,9 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchove
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.emoji.JumboEmoji;
import org.thoughtcrime.securesms.fonts.SignalSymbols;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Weight;
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mms.Slide;
@@ -193,69 +197,69 @@ public abstract class MessageRecord extends DisplayRecord {
return getGv2ChangeDescription(context, getBody(), recipientClickHandler);
}
} else if (isGroupUpdate() && isOutgoing()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), R.drawable.ic_update_group_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_updated_group), Glyph.GROUP);
} else if (isGroupUpdate()) {
return fromRecipient(getFromRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), R.drawable.ic_update_group_16);
return fromRecipient(getFromRecipient(), r -> GroupUtil.getNonV2GroupDescription(context, getBody()).toString(r), Glyph.GROUP);
} else if (isGroupQuit() && isOutgoing()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_left_group), R.drawable.ic_update_group_leave_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_left_group), Glyph.LEAVE);
} else if (isGroupQuit()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), R.drawable.ic_update_group_leave_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.ConversationItem_group_action_left, r.getDisplayName(context)), Glyph.LEAVE);
} else if (isIncomingAudioCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_voice_call), getCallDateString(context)), R.drawable.ic_update_audio_call_incoming_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_voice_call), getCallDateString(context)), Glyph.PHONE);
} else if (isIncomingVideoCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_video_call), getCallDateString(context)), R.drawable.ic_update_video_call_incoming_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_incoming_video_call), getCallDateString(context)), Glyph.VIDEO_CAMERA);
} else if (isOutgoingAudioCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_outgoing_voice_call), getCallDateString(context)), R.drawable.ic_update_audio_call_outgoing_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_outgoing_voice_call), getCallDateString(context)), Glyph.PHONE);
} else if (isOutgoingVideoCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_outgoing_video_call), getCallDateString(context)), R.drawable.ic_update_video_call_outgoing_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_outgoing_video_call), getCallDateString(context)), Glyph.VIDEO_CAMERA);
} else if (isMissedAudioCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_voice_call), getCallDateString(context)), R.drawable.ic_update_audio_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_voice_call), getCallDateString(context)), Glyph.PHONE, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
} else if (isMissedVideoCall()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_video_call), getCallDateString(context)), R.drawable.ic_update_video_call_missed_16, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(R.string.MessageRecord_missed_video_call), getCallDateString(context)), Glyph.VIDEO_CAMERA, ContextCompat.getColor(context, R.color.core_red_shade), ContextCompat.getColor(context, R.color.core_red));
} else if (isGroupCall()) {
return getGroupCallUpdateDescription(context, getBody(), true);
} else if (isJoined()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getFromRecipient().getDisplayName(context)), R.drawable.ic_update_group_add_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_s_joined_signal, getFromRecipient().getDisplayName(context)), Glyph.PERSON_PLUS);
} else if (isExpirationTimerUpdate()) {
int seconds = (int)(getExpiresIn() / 1000);
if (seconds <= 0) {
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), R.drawable.ic_update_timer_disabled_16)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), R.drawable.ic_update_timer_disabled_16);
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_disabled_disappearing_messages), Glyph.TIMER_SLASH)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_disabled_disappearing_messages, r.getDisplayName(context)), Glyph.TIMER_SLASH);
}
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), R.drawable.ic_update_timer_16)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), R.drawable.ic_update_timer_16);
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_set_disappearing_message_time_to_s, time), Glyph.TIMER)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_set_disappearing_message_time_to_s, r.getDisplayName(context), time), Glyph.TIMER);
} else if (isIdentityUpdate()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), Glyph.SAFETY_NUMBER);
} else if (isIdentityVerified()) {
if (isOutgoing()) return fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), R.drawable.ic_safety_number_16);
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), R.drawable.ic_safety_number_16);
if (isOutgoing()) return fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified, r.getDisplayName(context)), Glyph.SAFETY_NUMBER);
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_verified_from_another_device, r.getDisplayName(context)), Glyph.SAFETY_NUMBER);
} else if (isIdentityDefault()) {
if (isOutgoing()) return fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), R.drawable.ic_update_info_16);
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), R.drawable.ic_update_info_16);
if (isOutgoing()) return fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified, r.getDisplayName(context)), Glyph.INFO);
else return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_you_marked_your_safety_number_with_s_unverified_from_another_device, r.getDisplayName(context)), Glyph.INFO);
} else if (isProfileChange()) {
return getProfileChangeDescription(context);
} else if (isChangeNumber()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), R.drawable.ic_phone_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_changed_their_phone_number, r.getDisplayName(context)), Glyph.PHONE);
} else if (isReleaseChannelDonationRequest()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_like_this_new_feature_help_support_signal_with_a_one_time_donation), 0);
return staticUpdateDescription(context.getString(R.string.MessageRecord_like_this_new_feature_help_support_signal_with_a_one_time_donation), null);
} else if (isEndSession()) {
if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), R.drawable.ic_update_info_16);
else return fromRecipient(getFromRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), R.drawable.ic_update_info_16);
if (isOutgoing()) return staticUpdateDescription(context.getString(R.string.SmsMessageRecord_secure_session_reset), Glyph.INFO);
else return fromRecipient(getFromRecipient(), r-> context.getString(R.string.SmsMessageRecord_secure_session_reset_s, r.getDisplayName(context)), Glyph.INFO);
} else if (isGroupV1MigrationEvent()) {
return getGroupMigrationEventDescription(context);
} else if (isChatSessionRefresh()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_chat_session_refreshed), R.drawable.ic_refresh_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_chat_session_refreshed), Glyph.REFRESH);
} else if (isBadDecryptType()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), R.drawable.ic_error_outline_14);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_a_message_from_s_couldnt_be_delivered, r.getDisplayName(context)), Glyph.ERROR);
} else if (isThreadMergeEventType()) {
try {
ThreadMergeEvent event = ThreadMergeEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody()));
if (event.previousE164.isEmpty()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), R.drawable.ic_thread_merge_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_another_chat_has_been_merged, r.getDisplayName(context)), Glyph.MERGE);
} else {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), SignalE164Util.prettyPrint(event.previousE164)), R.drawable.ic_thread_merge_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_message_history_with_s_and_their_number_s_has_been_merged, r.getDisplayName(context), SignalE164Util.prettyPrint(event.previousE164)), Glyph.MERGE);
}
} catch (IOException e) {
throw new AssertionError(e);
@@ -265,30 +269,30 @@ public abstract class MessageRecord extends DisplayRecord {
SessionSwitchoverEvent event = SessionSwitchoverEvent.ADAPTER.decode(Base64.decodeOrThrow(getBody()));
if (event.e164.isEmpty()) {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), R.drawable.ic_update_safety_number_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_your_safety_number_with_s_has_changed, r.getDisplayName(context)), Glyph.SAFETY_NUMBER);
} else {
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, SignalE164Util.prettyPrint(event.e164), r.getDisplayName(context)), R.drawable.ic_update_info_16);
return fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_s_belongs_to_s, SignalE164Util.prettyPrint(event.e164), r.getDisplayName(context)), Glyph.INFO);
}
} catch (IOException e) {
throw new AssertionError(e);
}
} else if (isSmsExportType()) {
int messageResource = R.string.MessageRecord__you_can_no_longer_send_sms_messages_in_signal;
return fromRecipient(getFromRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), R.drawable.ic_update_info_16);
return fromRecipient(getFromRecipient(), r -> context.getString(messageResource, r.getDisplayName(context)), Glyph.INFO);
} else if (isPaymentsRequestToActivate()) {
return isOutgoing() ? fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
return isOutgoing() ? fromRecipient(getToRecipient(), r -> context.getString(R.string.MessageRecord_you_sent_request, r.getShortDisplayName(context)), Glyph.ACTIVATE_PAYMENTS)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_wants_you_to_activate_payments, r.getShortDisplayName(context)), Glyph.ACTIVATE_PAYMENTS);
} else if (isPaymentsActivated()) {
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_activated_payments), R.drawable.ic_card_activate_payments)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), R.drawable.ic_card_activate_payments);
return isOutgoing() ? staticUpdateDescription(context.getString(R.string.MessageRecord_you_activated_payments), Glyph.ACTIVATE_PAYMENTS)
: fromRecipient(getFromRecipient(), r -> context.getString(R.string.MessageRecord_can_accept_payments, r.getShortDisplayName(context)), Glyph.ACTIVATE_PAYMENTS);
} else if (isReportedSpam()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_reported_as_spam), R.drawable.symbol_spam_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_reported_as_spam), Glyph.SPAM);
} else if (isMessageRequestAccepted()) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_accepted_the_message_request), R.drawable.symbol_thread_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_you_accepted_the_message_request), Glyph.THREAD);
} else if (isBlocked()) {
return staticUpdateDescription(context.getString(isGroupV2() ? R.string.MessageRecord_you_blocked_this_group : R.string.MessageRecord_you_blocked_this_person), R.drawable.symbol_block_16);
return staticUpdateDescription(context.getString(isGroupV2() ? R.string.MessageRecord_you_blocked_this_group : R.string.MessageRecord_you_blocked_this_person), Glyph.BLOCK);
} else if (isUnblocked()) {
return staticUpdateDescription(context.getString(isGroupV2() ? R.string.MessageRecord_you_unblocked_this_group : R.string.MessageRecord_you_unblocked_this_person) , R.drawable.symbol_thread_16);
return staticUpdateDescription(context.getString(isGroupV2() ? R.string.MessageRecord_you_unblocked_this_group : R.string.MessageRecord_you_unblocked_this_person) , Glyph.THREAD);
}
return null;
@@ -352,7 +356,7 @@ public abstract class MessageRecord extends DisplayRecord {
return getGv2ChangeDescription(context, decryptedGroupV2Context, recipientClickHandler);
} catch (IOException | IllegalArgumentException | IllegalStateException e) {
Log.w(TAG, "GV2 Message update detail could not be read", e);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), Glyph.GROUP);
}
}
@@ -368,7 +372,7 @@ public abstract class MessageRecord extends DisplayRecord {
Log.w(TAG, "GV2 Update Description missing group change update!");
}
}
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), Glyph.GROUP);
}
public static @NonNull UpdateDescription getGv2ChangeDescription(@NonNull Context context, @NonNull DecryptedGroupV2Context decryptedGroupV2Context, @Nullable Consumer<RecipientId> recipientClickHandler) {
@@ -386,20 +390,20 @@ public abstract class MessageRecord extends DisplayRecord {
}
if (selfCreatedGroup(decryptedGroupV2Context.change)) {
newGroupDescriptions.add(staticUpdateDescription(context.getString(R.string.MessageRecord_invite_friends_to_this_group), 0));
newGroupDescriptions.add(staticUpdateDescription(context.getString(R.string.MessageRecord_invite_friends_to_this_group), null));
}
return concatWithNewLinesCapped(context, newGroupDescriptions);
}
} catch (IllegalArgumentException | IllegalStateException e) {
Log.w(TAG, "GV2 Message update detail could not be read", e);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), Glyph.GROUP);
}
}
private static @NonNull UpdateDescription concatWithNewLinesCapped(@NonNull Context context, @NonNull List<UpdateDescription> updateDescriptions) {
if (updateDescriptions.size() > 100) {
// Arbitrary update description collapse cap, otherwise the long string can cause issues
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), R.drawable.ic_update_group_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_group_updated), Glyph.GROUP);
}
return UpdateDescription.concatWithNewLines(updateDescriptions);
}
@@ -437,25 +441,25 @@ public abstract class MessageRecord extends DisplayRecord {
protected static @NonNull UpdateDescription fromRecipient(@NonNull Recipient recipient,
@NonNull Function<Recipient, String> stringGenerator,
@DrawableRes int iconResource)
Glyph glyph)
{
return UpdateDescription.mentioning(Collections.singletonList(recipient.getAci().orElse(ACI.UNKNOWN)),
() -> new SpannableString(stringGenerator.apply(recipient.resolve())),
iconResource);
glyph);
}
protected static @NonNull UpdateDescription staticUpdateDescription(@NonNull String string,
@DrawableRes int iconResource)
Glyph glyph)
{
return UpdateDescription.staticDescription(string, iconResource);
return UpdateDescription.staticDescription(string, glyph);
}
protected static @NonNull UpdateDescription staticUpdateDescription(@NonNull String string,
@DrawableRes int iconResource,
Glyph glyph,
@ColorInt int lightTint,
@ColorInt int darkTint)
{
return UpdateDescription.staticDescription(string, iconResource, lightTint, darkTint);
return UpdateDescription.staticDescription(string, glyph, lightTint, darkTint);
}
private @NonNull UpdateDescription getProfileChangeDescription(@NonNull Context context) {
@@ -486,9 +490,9 @@ public abstract class MessageRecord extends DisplayRecord {
updateMessage = context.getString(R.string.MessageRecord_changed_their_profile_name_to, previousName, newName);
}
return staticUpdateDescription(updateMessage, R.drawable.ic_update_profile_16);
return staticUpdateDescription(updateMessage, Glyph.PERSON);
} else if (profileChangeDetails.deprecatedLearnedProfileName != null) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_started_this_chat, profileChangeDetails.deprecatedLearnedProfileName.previous), R.drawable.symbol_thread_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_started_this_chat, profileChangeDetails.deprecatedLearnedProfileName.previous), Glyph.THREAD);
} else if (profileChangeDetails.learnedProfileName != null) {
String previouslyKnownAs;
if (!Util.isEmpty(profileChangeDetails.learnedProfileName.e164)) {
@@ -498,31 +502,31 @@ public abstract class MessageRecord extends DisplayRecord {
}
if (!Util.isEmpty(previouslyKnownAs)) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_started_this_chat, previouslyKnownAs), R.drawable.symbol_thread_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_started_this_chat, previouslyKnownAs), Glyph.THREAD);
}
}
}
return staticUpdateDescription(context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context)), R.drawable.ic_update_profile_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_changed_their_profile, getFromRecipient().getDisplayName(context)), Glyph.PERSON);
}
private UpdateDescription getGroupMigrationEventDescription(@NonNull Context context) {
if (Util.isEmpty(getBody())) {
return staticUpdateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), R.drawable.ic_update_group_role_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_this_group_was_updated_to_a_new_group), Glyph.MEGAPHONE);
} else {
GroupMigrationMembershipChange change = getGroupV1MigrationMembershipChanges();
List<UpdateDescription> updates = new ArrayList<>(2);
if (change.getPending().size() == 1 && change.getPending().get(0).equals(Recipient.self().getId())) {
updates.add(staticUpdateDescription(context.getString(R.string.MessageRecord_you_couldnt_be_added_to_the_new_group_and_have_been_invited_to_join), R.drawable.ic_update_group_add_16));
updates.add(staticUpdateDescription(context.getString(R.string.MessageRecord_you_couldnt_be_added_to_the_new_group_and_have_been_invited_to_join), Glyph.PERSON_PLUS));
} else if (change.getPending().size() > 0) {
int count = change.getPending().size();
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, count, count), R.drawable.ic_update_group_add_16));
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_invited, count, count), Glyph.PERSON_PLUS));
}
if (change.getDropped().size() > 0) {
int count = change.getDropped().size();
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, count, count), R.drawable.ic_update_group_remove_16));
updates.add(staticUpdateDescription(context.getResources().getQuantityString(R.plurals.MessageRecord_members_couldnt_be_added_to_the_new_group_and_have_been_removed, count, count), Glyph.PERSON_MINUS));
}
return concatWithNewLinesCapped(context, updates);
@@ -540,7 +544,7 @@ public abstract class MessageRecord extends DisplayRecord {
UpdateDescription.SpannableFactory stringFactory = new GroupCallUpdateMessageFactory(context, joinedMembers, withTime, groupCallUpdateDetails);
return UpdateDescription.mentioning(joinedMembers, stringFactory, R.drawable.ic_video_16);
return UpdateDescription.mentioning(joinedMembers, stringFactory, Glyph.VIDEO_CAMERA);
}
public boolean isGroupV2DescriptionUpdate() {

View File

@@ -28,6 +28,8 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
import org.thoughtcrime.securesms.database.model.databaseprotos.CryptoValue;
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge;
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras;
import org.thoughtcrime.securesms.fonts.SignalSymbols;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
@@ -250,20 +252,20 @@ public class MmsMessageRecord extends MessageRecord {
if (call.getDirection() == CallTable.Direction.OUTGOING) {
if (call.getType() == CallTable.Type.AUDIO_CALL) {
int updateString = R.string.MessageRecord_outgoing_voice_call;
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_audio_call_outgoing_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), Glyph.PHONE);
} else {
int updateString = R.string.MessageRecord_outgoing_video_call;
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), R.drawable.ic_update_video_call_outgoing_16);
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), Glyph.VIDEO_CAMERA);
}
} else {
boolean isVideoCall = call.getType() == CallTable.Type.VIDEO_CALL;
if (accepted || !call.isDisplayedAsMissedCallInUi()) {
int updateString = isVideoCall ? R.string.MessageRecord_incoming_video_call : R.string.MessageRecord_incoming_voice_call;
int icon = isVideoCall ? R.drawable.ic_update_video_call_incoming_16 : R.drawable.ic_update_audio_call_incoming_16;
Glyph icon = isVideoCall ? Glyph.VIDEO_CAMERA : Glyph.PHONE;
return staticUpdateDescription(context.getString(R.string.MessageRecord_call_message_with_date, context.getString(updateString), callDateString), icon);
} else {
int icon = isVideoCall ? R.drawable.ic_update_video_call_missed_16 : R.drawable.ic_update_audio_call_missed_16;
Glyph icon = isVideoCall ? Glyph.VIDEO_CAMERA : Glyph.PHONE;
int message;
if (call.getEvent() == CallTable.Event.MISSED_NOTIFICATION_PROFILE) {
message = isVideoCall ? R.string.MessageRecord_missed_video_call_notification_profile : R.string.MessageRecord_missed_voice_call_notification_profile;

View File

@@ -11,7 +11,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import org.whispersystems.signalservice.api.push.ServiceId.ACI;
import org.thoughtcrime.securesms.fonts.SignalSymbols;
import org.thoughtcrime.securesms.fonts.SignalSymbols.Glyph;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.util.Collection;
@@ -33,14 +34,14 @@ public final class UpdateDescription {
private final Collection<ServiceId> mentioned;
private final SpannableFactory stringFactory;
private final Spannable staticString;
private final int lightIconResource;
private final Glyph glyph;
private final int lightTint;
private final int darkTint;
private UpdateDescription(@NonNull Collection<ServiceId> mentioned,
@Nullable SpannableFactory stringFactory,
@Nullable Spannable staticString,
@DrawableRes int iconResource,
@NonNull Glyph glyph,
@ColorInt int lightTint,
@ColorInt int darkTint)
{
@@ -50,7 +51,7 @@ public final class UpdateDescription {
this.mentioned = mentioned;
this.stringFactory = stringFactory;
this.staticString = staticString;
this.lightIconResource = iconResource;
this.glyph = glyph;
this.lightTint = lightTint;
this.darkTint = darkTint;
}
@@ -64,43 +65,43 @@ public final class UpdateDescription {
*/
public static UpdateDescription mentioning(@NonNull Collection<ServiceId> mentioned,
@NonNull SpannableFactory stringFactory,
@DrawableRes int iconResource)
Glyph glyph)
{
return new UpdateDescription(mentioned.stream().filter(ServiceId::isValid).collect(Collectors.toList()),
stringFactory,
null,
iconResource,
glyph,
0,
0);
}
/**
* Create an update description that's string value is fixed.
* Create an update description that's string value is fixed with a start glyph.
*/
public static UpdateDescription staticDescription(@NonNull String staticString,
@DrawableRes int iconResource)
Glyph glyph)
{
return new UpdateDescription(Collections.emptyList(), null, new SpannableString(staticString), iconResource, 0, 0);
return new UpdateDescription(Collections.emptyList(), null, new SpannableString(staticString), glyph, 0, 0);
}
/**
* Create an update description that's string value is fixed.
*/
public static UpdateDescription staticDescription(@NonNull Spannable staticString,
@DrawableRes int iconResource)
Glyph glyph)
{
return new UpdateDescription(Collections.emptyList(), null, staticString, iconResource, 0, 0);
return new UpdateDescription(Collections.emptyList(), null, staticString, glyph, 0, 0);
}
/**
* Create an update description that's string value is fixed with a specific tint color.
*/
public static UpdateDescription staticDescription(@NonNull String staticString,
@DrawableRes int iconResource,
Glyph glyph,
@ColorInt int lightTint,
@ColorInt int darkTint)
{
return new UpdateDescription(Collections.emptyList(), null, new SpannableString(staticString), iconResource, lightTint, darkTint);
return new UpdateDescription(Collections.emptyList(), null, new SpannableString(staticString), glyph, lightTint, darkTint);
}
public boolean isStringStatic() {
@@ -131,8 +132,8 @@ public final class UpdateDescription {
return mentioned;
}
public @DrawableRes int getIconResource() {
return lightIconResource;
public @Nullable Glyph getGlyph() {
return glyph;
}
public @ColorInt int getLightTint() {
@@ -154,7 +155,7 @@ public final class UpdateDescription {
if (allAreStatic(updateDescriptions)) {
return UpdateDescription.staticDescription(concatStaticLines(updateDescriptions),
updateDescriptions.get(0).getIconResource()
updateDescriptions.get(0).getGlyph()
);
}
@@ -166,7 +167,7 @@ public final class UpdateDescription {
return UpdateDescription.mentioning(allMentioned,
() -> concatLines(updateDescriptions),
updateDescriptions.get(0).getIconResource());
updateDescriptions.get(0).getGlyph());
}
private static boolean allAreStatic(@NonNull Collection<UpdateDescription> updateDescriptions) {

View File

@@ -27,12 +27,6 @@ import org.thoughtcrime.securesms.util.ViewUtil
object SignalSymbols {
enum class Glyph(val unicode: Char) {
CHECKMARK('\u2713'),
CHEVRON_LEFT('\uE024'),
CHEVRON_RIGHT('\uE025'),
PERSON_CIRCLE('\uE05E'),
LOCK('\uE041'),
LOCK_OPEN('\uE07D'),
LOGO('\uE000'),
ALBUM('\uE001'),
APPEARANCE('\uE031'),
@@ -90,6 +84,8 @@ object SignalSymbols {
CHECK('\u2713'),
CHECK_CIRCLE('\uE022'),
CHECK_SQUARE('\uE023'),
CHEVRON_LEFT('\uE024'),
CHEVRON_RIGHT('\uE025'),
CHEVRON_UP('\uE026'),
CHEVRON_DOWN('\uE027'),
CHEVRON_CIRCLE_LEFT('\uE028'),
@@ -124,6 +120,8 @@ object SignalSymbols {
LINK_ANDROID('\uE03F'),
LINK_BROKEN('\uE057'),
LINK_SLASH('\uE040'),
LOCK('\uE041'),
LOCK_OPEN('\uE07D'),
MEGAPHONE('\uE042'),
MERGE('\uE043'),
MESSAGE_STATUS_SENDING('\uE044'),
@@ -156,6 +154,7 @@ object SignalSymbols {
OFFICIAL_BADGE_FILL('\uE087'),
OUTGOING('\uE05C'),
PERSON('\uE05D'),
PERSON_CIRCLE('\uE05E'),
PERSON_CHECK('\uE05F'),
PERSON_X('\uE060'),
PERSON_PLUS('\uE061'),
@@ -187,7 +186,11 @@ object SignalSymbols {
VIEW_ONCE_VIEWED('\uE07A'),
X('\u00D7'),
X_CIRCLE('\u2297'),
X_SQUARE('\u2327')
X_SQUARE('\u2327'),
REFRESH('\uE000'),
ACTIVATE_PAYMENTS('\uE000'),
CALENDAR('\uE000')
}
enum class Weight {

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/signal_inverse_transparent_40">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="#000000" />
<corners android:radius="18dp" />
</shape>
</item>
<item android:drawable="@drawable/checkable_outline" />
</ripple>

View File

@@ -1,14 +0,0 @@
<!--
~ Copyright 2024 Signal Messenger, LLC
~ SPDX-License-Identifier: AGPL-3.0-only
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M18.97 5.26c0.4 0.26 0.53 0.8 0.27 1.21l-8.32 13c-0.16 0.24-0.42 0.4-0.7 0.4-0.28 0.02-0.55-0.1-0.73-0.33l-4.68-5.98c-0.3-0.38-0.23-0.93 0.15-1.23 0.38-0.3 0.93-0.23 1.23 0.15l3.92 5 7.65-11.95c0.26-0.4 0.8-0.53 1.21-0.27Z"/>
</vector>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<corners android:radius="18dp" />
<stroke android:color="@color/checkable_stroke_color" android:width="1dp" />
</shape>

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/checkable_outline" android:state_checked="true" />
</selector>

View File

@@ -26,28 +26,28 @@ public final class UpdateDescriptionTest {
@Test
public void staticDescription_byGetStaticString() {
UpdateDescription description = UpdateDescription.staticDescription("update", 0);
UpdateDescription description = UpdateDescription.staticDescription("update", null);
assertEquals("update", description.getStaticSpannable().toString());
}
@Test
public void staticDescription_has_empty_mentions() {
UpdateDescription description = UpdateDescription.staticDescription("update", 0);
UpdateDescription description = UpdateDescription.staticDescription("update", null);
assertTrue(description.getMentioned().isEmpty());
}
@Test
public void staticDescription_byString() {
UpdateDescription description = UpdateDescription.staticDescription("update", 0);
UpdateDescription description = UpdateDescription.staticDescription("update", null);
assertEquals("update", description.getSpannable().toString());
}
@Test(expected = UnsupportedOperationException.class)
public void stringFactory_cannot_call_static_string() {
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), () -> new SpannableString("update"), 0);
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), () -> new SpannableString("update"), null);
description.getStaticSpannable();
}
@@ -61,7 +61,7 @@ public final class UpdateDescriptionTest {
return new SpannableString("update");
};
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, 0);
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, null);
assertEquals(0, factoryCalls.get());
@@ -75,7 +75,7 @@ public final class UpdateDescriptionTest {
public void stringFactory_reevaluated_on_every_call() {
AtomicInteger factoryCalls = new AtomicInteger();
UpdateDescription.SpannableFactory stringFactory = () -> new SpannableString( "call" + factoryCalls.incrementAndGet());
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, 0);
UpdateDescription description = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory, null);
assertEquals("call1", description.getSpannable().toString());
assertEquals("call2", description.getSpannable().toString());
@@ -84,8 +84,8 @@ public final class UpdateDescriptionTest {
@Test
public void concat_static_lines() {
UpdateDescription description1 = UpdateDescription.staticDescription("update1", 0);
UpdateDescription description2 = UpdateDescription.staticDescription("update2", 0);
UpdateDescription description1 = UpdateDescription.staticDescription("update1", null);
UpdateDescription description2 = UpdateDescription.staticDescription("update2", null);
UpdateDescription description = UpdateDescription.concatWithNewLines(Arrays.asList(description1, description2));
@@ -96,7 +96,7 @@ public final class UpdateDescriptionTest {
@Test
public void concat_single_does_not_make_new_object() {
UpdateDescription description = UpdateDescription.staticDescription("update1", 0);
UpdateDescription description = UpdateDescription.staticDescription("update1", null);
UpdateDescription concat = UpdateDescription.concatWithNewLines(Collections.singletonList(description));
@@ -109,8 +109,8 @@ public final class UpdateDescriptionTest {
AtomicInteger factoryCalls2 = new AtomicInteger();
UpdateDescription.SpannableFactory stringFactory1 = () -> new SpannableString("update." + factoryCalls1.incrementAndGet());
UpdateDescription.SpannableFactory stringFactory2 = () -> new SpannableString("update." + factoryCalls2.incrementAndGet());
UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, 0);
UpdateDescription description2 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, 0);
UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, null);
UpdateDescription description2 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, null);
factoryCalls1.set(10);
factoryCalls2.set(20);
@@ -130,9 +130,9 @@ public final class UpdateDescriptionTest {
AtomicInteger factoryCalls2 = new AtomicInteger();
UpdateDescription.SpannableFactory stringFactory1 = () -> new SpannableString("update." + factoryCalls1.incrementAndGet());
UpdateDescription.SpannableFactory stringFactory2 = () -> new SpannableString("update." + factoryCalls2.incrementAndGet());
UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, 0);
UpdateDescription description2 = UpdateDescription.staticDescription("static", 0);
UpdateDescription description3 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, 0);
UpdateDescription description1 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory1, null);
UpdateDescription description2 = UpdateDescription.staticDescription("static", null);
UpdateDescription description3 = UpdateDescription.mentioning(Collections.singletonList(ACI.from(UUID.randomUUID())), stringFactory2, null);
factoryCalls1.set(100);
factoryCalls2.set(200);