mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 11:18:35 +00:00
Refactor ThreadRecord.
This commit is contained in:
parent
1cd6b58ece
commit
1b01196ec6
@ -22,7 +22,9 @@ import android.graphics.Typeface;
|
|||||||
import android.graphics.drawable.RippleDrawable;
|
import android.graphics.drawable.RippleDrawable;
|
||||||
import android.os.Build.VERSION;
|
import android.os.Build.VERSION;
|
||||||
import android.os.Build.VERSION_CODES;
|
import android.os.Build.VERSION_CODES;
|
||||||
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -41,6 +43,9 @@ import org.thoughtcrime.securesms.components.DeliveryStatusView;
|
|||||||
import org.thoughtcrime.securesms.components.FromTextView;
|
import org.thoughtcrime.securesms.components.FromTextView;
|
||||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||||
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
||||||
|
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||||
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||||
@ -48,6 +53,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||||||
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
|
||||||
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
|
import org.thoughtcrime.securesms.conversationlist.model.MessageResult;
|
||||||
import org.thoughtcrime.securesms.util.DateUtils;
|
import org.thoughtcrime.securesms.util.DateUtils;
|
||||||
|
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.util.SearchUtil;
|
import org.thoughtcrime.securesms.util.SearchUtil;
|
||||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
@ -94,7 +101,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
|
|
||||||
private final RecipientForeverObserver groupAddedByObserver = adder -> {
|
private final RecipientForeverObserver groupAddedByObserver = adder -> {
|
||||||
if (isAttachedToWindow() && subjectView != null && thread != null) {
|
if (isAttachedToWindow() && subjectView != null && thread != null) {
|
||||||
subjectView.setText(thread.getDisplayBody(getContext()));
|
subjectView.setText(getThreadDisplayBody(getContext(), thread));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -176,7 +183,7 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
this.typingView.stopAnimation();
|
this.typingView.stopAnimation();
|
||||||
|
|
||||||
this.subjectView.setVisibility(VISIBLE);
|
this.subjectView.setVisibility(VISIBLE);
|
||||||
this.subjectView.setText(getTrimmedSnippet(thread.getDisplayBody(getContext())));
|
this.subjectView.setText(getTrimmedSnippet(getThreadDisplayBody(getContext(), thread)));
|
||||||
|
|
||||||
if (thread.getGroupAddedBy() != null) {
|
if (thread.getGroupAddedBy() != null) {
|
||||||
groupAddedBy = Recipient.live(thread.getGroupAddedBy());
|
groupAddedBy = Recipient.live(thread.getGroupAddedBy());
|
||||||
@ -377,6 +384,99 @@ public class ConversationListItem extends RelativeLayout
|
|||||||
setRippleColor(recipient);
|
setRippleColor(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static SpannableString getThreadDisplayBody(@NonNull Context context, @NonNull ThreadRecord thread) {
|
||||||
|
if (thread.getGroupAddedBy() != null) {
|
||||||
|
return emphasisAdded(context.getString(thread.isGv2Invite() ? R.string.ThreadRecord_s_invited_you_to_the_group
|
||||||
|
: R.string.ThreadRecord_s_added_you_to_the_group,
|
||||||
|
Recipient.live(thread.getGroupAddedBy()).get().getDisplayName(context)));
|
||||||
|
} else if (!thread.isMessageRequestAccepted()) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_message_request));
|
||||||
|
} else if (SmsDatabase.Types.isGroupUpdate(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_group_updated));
|
||||||
|
} else if (SmsDatabase.Types.isGroupQuit(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_left_the_group));
|
||||||
|
} else if (SmsDatabase.Types.isKeyExchangeType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ConversationListItem_key_exchange_message));
|
||||||
|
} else if (SmsDatabase.Types.isFailedDecryptType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_bad_encrypted_message));
|
||||||
|
} else if (SmsDatabase.Types.isNoRemoteSessionType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
|
||||||
|
} else if (SmsDatabase.Types.isEndSessionType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_secure_session_reset));
|
||||||
|
} else if (MmsSmsColumns.Types.isLegacyType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
||||||
|
} else if (MmsSmsColumns.Types.isDraftMessageType(thread.getType())) {
|
||||||
|
String draftText = context.getString(R.string.ThreadRecord_draft);
|
||||||
|
return emphasisAdded(draftText + " " + thread.getBody(), 0, draftText.length());
|
||||||
|
} else if (SmsDatabase.Types.isOutgoingCall(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_called));
|
||||||
|
} else if (SmsDatabase.Types.isIncomingCall(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_called_you));
|
||||||
|
} else if (SmsDatabase.Types.isMissedCall(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
|
||||||
|
} else if (SmsDatabase.Types.isJoinedType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, thread.getRecipient().toShortString(context)));
|
||||||
|
} else if (SmsDatabase.Types.isExpirationTimerUpdate(thread.getType())) {
|
||||||
|
int seconds = (int)(thread.getExpiresIn() / 1000);
|
||||||
|
if (seconds <= 0) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_messages_disabled));
|
||||||
|
}
|
||||||
|
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
||||||
|
} else if (SmsDatabase.Types.isIdentityUpdate(thread.getType())) {
|
||||||
|
if (thread.getRecipient().isGroup()) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
||||||
|
} else {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_your_safety_number_with_s_has_changed, thread.getRecipient().toShortString(context)));
|
||||||
|
}
|
||||||
|
} else if (SmsDatabase.Types.isIdentityVerified(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_verified));
|
||||||
|
} else if (SmsDatabase.Types.isIdentityDefault(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_unverified));
|
||||||
|
} else if (SmsDatabase.Types.isUnsupportedMessageType(thread.getType())) {
|
||||||
|
return emphasisAdded(context.getString(R.string.ThreadRecord_message_could_not_be_processed));
|
||||||
|
} else {
|
||||||
|
if (TextUtils.isEmpty(thread.getBody())) {
|
||||||
|
ThreadDatabase.Extra extra = thread.getExtra();
|
||||||
|
if (extra != null && extra.isSticker()) {
|
||||||
|
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_sticker)));
|
||||||
|
} else if (extra != null && extra.isViewOnce()) {
|
||||||
|
return new SpannableString(emphasisAdded(getViewOnceDescription(context, thread.getContentType())));
|
||||||
|
} else if (extra != null && extra.isRemoteDelete()) {
|
||||||
|
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_this_message_was_deleted)));
|
||||||
|
} else {
|
||||||
|
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new SpannableString(thread.getBody());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NonNull SpannableString emphasisAdded(String sequence) {
|
||||||
|
return emphasisAdded(sequence, 0, sequence.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NonNull SpannableString emphasisAdded(String sequence, int start, int end) {
|
||||||
|
SpannableString spannable = new SpannableString(sequence);
|
||||||
|
spannable.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return spannable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getViewOnceDescription(@NonNull Context context, @Nullable String contentType) {
|
||||||
|
if (MediaUtil.isViewOnceType(contentType)) {
|
||||||
|
return context.getString(R.string.ThreadRecord_view_once_media);
|
||||||
|
} else if (MediaUtil.isVideoType(contentType)) {
|
||||||
|
return context.getString(R.string.ThreadRecord_view_once_video);
|
||||||
|
} else {
|
||||||
|
return context.getString(R.string.ThreadRecord_view_once_photo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class ThumbnailPositioner implements Runnable {
|
private static class ThumbnailPositioner implements Runnable {
|
||||||
|
|
||||||
private final View thumbnailView;
|
private final View thumbnailView;
|
||||||
|
@ -848,30 +848,14 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ThreadRecord getCurrent() {
|
public ThreadRecord getCurrent() {
|
||||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID));
|
|
||||||
int distributionType = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE));
|
|
||||||
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_ID)));
|
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_ID)));
|
||||||
|
|
||||||
Recipient recipient = Recipient.live(recipientId).get();
|
Recipient recipient = Recipient.live(recipientId).get();
|
||||||
String body = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET));
|
|
||||||
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
|
|
||||||
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
|
int readReceiptCount = TextSecurePreferences.isReadReceiptsEnabled(context) ? cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.READ_RECEIPT_COUNT))
|
||||||
int unreadCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.UNREAD_COUNT));
|
: 0;
|
||||||
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
|
|
||||||
boolean archived = cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0;
|
|
||||||
int status = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS));
|
|
||||||
int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.DELIVERY_RECEIPT_COUNT));
|
|
||||||
int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.READ_RECEIPT_COUNT));
|
|
||||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN));
|
|
||||||
long lastSeen = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN));
|
|
||||||
Uri snippetUri = getSnippetUri(cursor);
|
|
||||||
String contentType = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_CONTENT_TYPE));
|
|
||||||
String extraString = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_EXTRAS));
|
String extraString = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_EXTRAS));
|
||||||
|
|
||||||
if (!TextSecurePreferences.isReadReceiptsEnabled(context)) {
|
|
||||||
readReceiptCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Extra extra = null;
|
Extra extra = null;
|
||||||
|
|
||||||
if (extraString != null) {
|
if (extraString != null) {
|
||||||
@ -882,9 +866,24 @@ public class ThreadDatabase extends Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ThreadRecord(body, snippetUri, contentType, extra, recipient, date, count,
|
return new ThreadRecord.Builder(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.ID)))
|
||||||
unreadCount, threadId, deliveryReceiptCount, status, type,
|
.setRecipient(recipient)
|
||||||
distributionType, archived, expiresIn, lastSeen, readReceiptCount);
|
.setType(cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE)))
|
||||||
|
.setDistributionType(cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.TYPE)))
|
||||||
|
.setBody(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET)))
|
||||||
|
.setDate(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE)))
|
||||||
|
.setArchived(cursor.getInt(cursor.getColumnIndex(ThreadDatabase.ARCHIVED)) != 0)
|
||||||
|
.setDeliveryStatus(cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.STATUS)))
|
||||||
|
.setDeliveryReceiptCount(cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.DELIVERY_RECEIPT_COUNT)))
|
||||||
|
.setReadReceiptCount(readReceiptCount)
|
||||||
|
.setExpiresIn(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.EXPIRES_IN)))
|
||||||
|
.setLastSeen(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.LAST_SEEN)))
|
||||||
|
.setSnippetUri(getSnippetUri(cursor))
|
||||||
|
.setContentType(cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_CONTENT_TYPE)))
|
||||||
|
.setCount(cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT)))
|
||||||
|
.setUnreadCount(cursor.getInt(cursor.getColumnIndexOrThrow(ThreadDatabase.UNREAD_COUNT)))
|
||||||
|
.setExtra(extra)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Uri getSnippetUri(Cursor cursor) {
|
private @Nullable Uri getSnippetUri(Cursor cursor) {
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
package org.thoughtcrime.securesms.database.model;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||||
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
|
|
||||||
|
final class StatusUtil {
|
||||||
|
private StatusUtil() {}
|
||||||
|
|
||||||
|
static boolean isDelivered(long deliveryStatus, int deliveryReceiptCount) {
|
||||||
|
return (deliveryStatus >= SmsDatabase.Status.STATUS_COMPLETE &&
|
||||||
|
deliveryStatus < SmsDatabase.Status.STATUS_PENDING) || deliveryReceiptCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isPending(long type) {
|
||||||
|
return MmsSmsColumns.Types.isPendingMessageType(type) &&
|
||||||
|
!MmsSmsColumns.Types.isIdentityVerified(type) &&
|
||||||
|
!MmsSmsColumns.Types.isIdentityDefault(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isFailed(long type, long deliveryStatus) {
|
||||||
|
return MmsSmsColumns.Types.isFailedMessageType(type) ||
|
||||||
|
MmsSmsColumns.Types.isPendingSecureSmsFallbackType(type) ||
|
||||||
|
deliveryStatus >= SmsDatabase.Status.STATUS_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isVerificationStatusChange(long type) {
|
||||||
|
return SmsDatabase.Types.isIdentityDefault(type) || SmsDatabase.Types.isIdentityVerified(type);
|
||||||
|
}
|
||||||
|
}
|
@ -17,36 +17,34 @@
|
|||||||
*/
|
*/
|
||||||
package org.thoughtcrime.securesms.database.model;
|
package org.thoughtcrime.securesms.database.model;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.Spannable;
|
|
||||||
import android.text.SpannableString;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.style.StyleSpan;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
|
||||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase.Extra;
|
import org.thoughtcrime.securesms.database.ThreadDatabase.Extra;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.ExpirationUtil;
|
import org.whispersystems.libsignal.util.guava.Preconditions;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message record model which represents thread heading messages.
|
* Represents an entry in the {@link org.thoughtcrime.securesms.database.ThreadDatabase}.
|
||||||
*
|
|
||||||
* @author Moxie Marlinspike
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ThreadRecord extends DisplayRecord {
|
public final class ThreadRecord {
|
||||||
|
|
||||||
private @Nullable final Uri snippetUri;
|
private final long threadId;
|
||||||
private @Nullable final String contentType;
|
private final String body;
|
||||||
private @Nullable final Extra extra;
|
private final Recipient recipient;
|
||||||
|
private final long type;
|
||||||
|
private final long date;
|
||||||
|
private final long deliveryStatus;
|
||||||
|
private final int deliveryReceiptCount;
|
||||||
|
private final int readReceiptCount;
|
||||||
|
private final Uri snippetUri;
|
||||||
|
private final String contentType;
|
||||||
|
private final Extra extra;
|
||||||
private final long count;
|
private final long count;
|
||||||
private final int unreadCount;
|
private final int unreadCount;
|
||||||
private final int distributionType;
|
private final int distributionType;
|
||||||
@ -54,114 +52,48 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
private final long expiresIn;
|
private final long expiresIn;
|
||||||
private final long lastSeen;
|
private final long lastSeen;
|
||||||
|
|
||||||
public ThreadRecord(@NonNull String body, @Nullable Uri snippetUri,
|
private ThreadRecord(@NonNull Builder builder) {
|
||||||
@Nullable String contentType, @Nullable Extra extra,
|
this.threadId = builder.threadId;
|
||||||
@NonNull Recipient recipient, long date, long count, int unreadCount,
|
this.body = builder.body;
|
||||||
long threadId, int deliveryReceiptCount, int status, long snippetType,
|
this.recipient = builder.recipient;
|
||||||
int distributionType, boolean archived, long expiresIn, long lastSeen,
|
this.date = builder.date;
|
||||||
int readReceiptCount)
|
this.type = builder.type;
|
||||||
{
|
this.deliveryStatus = builder.deliveryStatus;
|
||||||
super(body, recipient, date, date, threadId, status, deliveryReceiptCount, snippetType, readReceiptCount);
|
this.deliveryReceiptCount = builder.deliveryReceiptCount;
|
||||||
this.snippetUri = snippetUri;
|
this.readReceiptCount = builder.readReceiptCount;
|
||||||
this.contentType = contentType;
|
this.snippetUri = builder.snippetUri;
|
||||||
this.extra = extra;
|
this.contentType = builder.contentType;
|
||||||
this.count = count;
|
this.extra = builder.extra;
|
||||||
this.unreadCount = unreadCount;
|
this.count = builder.count;
|
||||||
this.distributionType = distributionType;
|
this.unreadCount = builder.unreadCount;
|
||||||
this.archived = archived;
|
this.distributionType = builder.distributionType;
|
||||||
this.expiresIn = expiresIn;
|
this.archived = builder.archived;
|
||||||
this.lastSeen = lastSeen;
|
this.expiresIn = builder.expiresIn;
|
||||||
|
this.lastSeen = builder.lastSeen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getThreadId() {
|
||||||
|
return threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull Recipient getRecipient() {
|
||||||
|
return recipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Uri getSnippetUri() {
|
public @Nullable Uri getSnippetUri() {
|
||||||
return snippetUri;
|
return snippetUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public @NonNull String getBody() {
|
||||||
public SpannableString getDisplayBody(@NonNull Context context) {
|
return body;
|
||||||
if (getGroupAddedBy() != null) {
|
|
||||||
return emphasisAdded(context.getString(isGv2Invite() ? R.string.ThreadRecord_s_invited_you_to_the_group
|
|
||||||
: R.string.ThreadRecord_s_added_you_to_the_group,
|
|
||||||
Recipient.live(getGroupAddedBy()).get().getDisplayName(context)));
|
|
||||||
} else if (!isMessageRequestAccepted()) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_message_request));
|
|
||||||
} else if (isGroupUpdate()) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_group_updated));
|
|
||||||
} else if (isGroupQuit()) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_left_the_group));
|
|
||||||
} else if (isKeyExchange()) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ConversationListItem_key_exchange_message));
|
|
||||||
} else if (SmsDatabase.Types.isFailedDecryptType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_bad_encrypted_message));
|
|
||||||
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
|
|
||||||
} else if (SmsDatabase.Types.isEndSessionType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_secure_session_reset));
|
|
||||||
} else if (MmsSmsColumns.Types.isLegacyType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.MessageRecord_message_encrypted_with_a_legacy_protocol_version_that_is_no_longer_supported));
|
|
||||||
} else if (MmsSmsColumns.Types.isDraftMessageType(type)) {
|
|
||||||
String draftText = context.getString(R.string.ThreadRecord_draft);
|
|
||||||
return emphasisAdded(draftText + " " + getBody(), 0, draftText.length());
|
|
||||||
} else if (SmsDatabase.Types.isOutgoingCall(type)) {
|
|
||||||
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_called));
|
|
||||||
} else if (SmsDatabase.Types.isIncomingCall(type)) {
|
|
||||||
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_called_you));
|
|
||||||
} else if (SmsDatabase.Types.isMissedCall(type)) {
|
|
||||||
return emphasisAdded(context.getString(org.thoughtcrime.securesms.R.string.ThreadRecord_missed_call));
|
|
||||||
} else if (SmsDatabase.Types.isJoinedType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_s_is_on_signal, getRecipient().toShortString(context)));
|
|
||||||
} else if (SmsDatabase.Types.isExpirationTimerUpdate(type)) {
|
|
||||||
int seconds = (int)(getExpiresIn() / 1000);
|
|
||||||
if (seconds <= 0) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_messages_disabled));
|
|
||||||
}
|
|
||||||
String time = ExpirationUtil.getExpirationDisplayValue(context, seconds);
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_disappearing_message_time_updated_to_s, time));
|
|
||||||
} else if (SmsDatabase.Types.isIdentityUpdate(type)) {
|
|
||||||
if (getRecipient().isGroup()) return emphasisAdded(context.getString(R.string.ThreadRecord_safety_number_changed));
|
|
||||||
else return emphasisAdded(context.getString(R.string.ThreadRecord_your_safety_number_with_s_has_changed, getRecipient().toShortString(context)));
|
|
||||||
} else if (SmsDatabase.Types.isIdentityVerified(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_verified));
|
|
||||||
} else if (SmsDatabase.Types.isIdentityDefault(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_you_marked_unverified));
|
|
||||||
} else if (SmsDatabase.Types.isUnsupportedMessageType(type)) {
|
|
||||||
return emphasisAdded(context.getString(R.string.ThreadRecord_message_could_not_be_processed));
|
|
||||||
} else {
|
|
||||||
if (TextUtils.isEmpty(getBody())) {
|
|
||||||
if (extra != null && extra.isSticker()) {
|
|
||||||
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_sticker)));
|
|
||||||
} else if (extra != null && extra.isViewOnce()) {
|
|
||||||
return new SpannableString(emphasisAdded(getViewOnceDescription(context, contentType)));
|
|
||||||
} else if (extra != null && extra.isRemoteDelete()) {
|
|
||||||
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_this_message_was_deleted)));
|
|
||||||
} else {
|
|
||||||
return new SpannableString(emphasisAdded(context.getString(R.string.ThreadRecord_media_message)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return new SpannableString(getBody());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpannableString emphasisAdded(String sequence) {
|
public @Nullable Extra getExtra() {
|
||||||
return emphasisAdded(sequence, 0, sequence.length());
|
return extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpannableString emphasisAdded(String sequence, int start, int end) {
|
public @Nullable String getContentType() {
|
||||||
SpannableString spannable = new SpannableString(sequence);
|
return contentType;
|
||||||
spannable.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC),
|
|
||||||
start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
return spannable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getViewOnceDescription(@NonNull Context context, @Nullable String contentType) {
|
|
||||||
if (MediaUtil.isViewOnceType(contentType)) {
|
|
||||||
return context.getString(R.string.ThreadRecord_view_once_media);
|
|
||||||
} else if (MediaUtil.isVideoType(contentType)) {
|
|
||||||
return context.getString(R.string.ThreadRecord_view_once_video);
|
|
||||||
} else {
|
|
||||||
return context.getString(R.string.ThreadRecord_view_once_photo);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCount() {
|
public long getCount() {
|
||||||
@ -173,13 +105,17 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getDate() {
|
public long getDate() {
|
||||||
return getDateReceived();
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isArchived() {
|
public boolean isArchived() {
|
||||||
return archived;
|
return archived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
public int getDistributionType() {
|
public int getDistributionType() {
|
||||||
return distributionType;
|
return distributionType;
|
||||||
}
|
}
|
||||||
@ -192,6 +128,38 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
return lastSeen;
|
return lastSeen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOutgoing() {
|
||||||
|
return MmsSmsColumns.Types.isOutgoingMessageType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOutgoingCall() {
|
||||||
|
return SmsDatabase.Types.isOutgoingCall(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVerificationStatusChange() {
|
||||||
|
return StatusUtil.isVerificationStatusChange(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPending() {
|
||||||
|
return StatusUtil.isPending(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFailed() {
|
||||||
|
return StatusUtil.isFailed(type, deliveryStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRemoteRead() {
|
||||||
|
return readReceiptCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPendingInsecureSmsFallback() {
|
||||||
|
return SmsDatabase.Types.isPendingInsecureSmsFallbackType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDelivered() {
|
||||||
|
return StatusUtil.isDelivered(deliveryStatus, deliveryReceiptCount);
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable RecipientId getGroupAddedBy() {
|
public @Nullable RecipientId getGroupAddedBy() {
|
||||||
if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy());
|
if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy());
|
||||||
else return null;
|
else return null;
|
||||||
@ -205,4 +173,121 @@ public class ThreadRecord extends DisplayRecord {
|
|||||||
if (extra != null) return extra.isMessageRequestAccepted();
|
if (extra != null) return extra.isMessageRequestAccepted();
|
||||||
else return true;
|
else return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private long threadId;
|
||||||
|
private String body;
|
||||||
|
private Recipient recipient;
|
||||||
|
private long type;
|
||||||
|
private long date;
|
||||||
|
private long deliveryStatus;
|
||||||
|
private int deliveryReceiptCount;
|
||||||
|
private int readReceiptCount;
|
||||||
|
private Uri snippetUri;
|
||||||
|
private String contentType;
|
||||||
|
private Extra extra;
|
||||||
|
private long count;
|
||||||
|
private int unreadCount;
|
||||||
|
private int distributionType;
|
||||||
|
private boolean archived;
|
||||||
|
private long expiresIn;
|
||||||
|
private long lastSeen;
|
||||||
|
|
||||||
|
public Builder(long threadId) {
|
||||||
|
this.threadId = threadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setBody(@NonNull String body) {
|
||||||
|
this.body = body;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setRecipient(@NonNull Recipient recipient) {
|
||||||
|
this.recipient = recipient;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setType(long type) {
|
||||||
|
this.type = type;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setThreadId(long threadId) {
|
||||||
|
this.threadId = threadId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDate(long date) {
|
||||||
|
this.date = date;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDeliveryStatus(long deliveryStatus) {
|
||||||
|
this.deliveryStatus = deliveryStatus;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDeliveryReceiptCount(int deliveryReceiptCount) {
|
||||||
|
this.deliveryReceiptCount = deliveryReceiptCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setReadReceiptCount(int readReceiptCount) {
|
||||||
|
this.readReceiptCount = readReceiptCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setSnippetUri(@Nullable Uri snippetUri) {
|
||||||
|
this.snippetUri = snippetUri;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setContentType(@Nullable String contentType) {
|
||||||
|
this.contentType = contentType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setExtra(@Nullable Extra extra) {
|
||||||
|
this.extra = extra;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setCount(long count) {
|
||||||
|
this.count = count;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setUnreadCount(int unreadCount) {
|
||||||
|
this.unreadCount = unreadCount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setDistributionType(int distributionType) {
|
||||||
|
this.distributionType = distributionType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setArchived(boolean archived) {
|
||||||
|
this.archived = archived;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setExpiresIn(long expiresIn) {
|
||||||
|
this.expiresIn = expiresIn;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setLastSeen(long lastSeen) {
|
||||||
|
this.lastSeen = lastSeen;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThreadRecord build() {
|
||||||
|
Preconditions.checkArgument(threadId > 0);
|
||||||
|
Preconditions.checkArgument(date > 0);
|
||||||
|
Preconditions.checkNotNull(body);
|
||||||
|
Preconditions.checkNotNull(recipient);
|
||||||
|
return new ThreadRecord(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user