mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 21:15:48 +00:00
Replace glyphs in group update messages.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user