Improve message requests, add megaphone.

This commit is contained in:
Alex Hart
2020-02-19 18:08:34 -04:00
committed by Greyson Parrelli
parent dc689d325b
commit 9e5f64c431
83 changed files with 2406 additions and 735 deletions

View File

@@ -19,16 +19,18 @@ package org.thoughtcrime.securesms.database;
import android.content.Context;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import org.thoughtcrime.securesms.R;
/**
* RecyclerView.Adapter that manages a Cursor, comparable to the CursorAdapter usable in ListView/GridView.
*/
@@ -47,8 +49,24 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
private @Nullable View footer;
private static class HeaderFooterViewHolder extends RecyclerView.ViewHolder {
public HeaderFooterViewHolder(View itemView) {
private ViewGroup container;
HeaderFooterViewHolder(@NonNull View itemView) {
super(itemView);
this.container = (ViewGroup) itemView;
}
void bind(@Nullable View view) {
unbind();
if (view != null) {
container.addView(view);
}
}
void unbind() {
container.removeAllViews();
}
}
@@ -135,6 +153,8 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
public final void onViewRecycled(@NonNull ViewHolder holder) {
if (!(holder instanceof HeaderFooterViewHolder)) {
onItemViewRecycled((VH)holder);
} else {
((HeaderFooterViewHolder) holder).unbind();
}
}
@@ -143,9 +163,11 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
@Override
public @NonNull final ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (viewType) {
case HEADER_TYPE: return new HeaderFooterViewHolder(header);
case FOOTER_TYPE: return new HeaderFooterViewHolder(footer);
default: return onCreateItemViewHolder(parent, viewType);
case HEADER_TYPE:
case FOOTER_TYPE:
return new HeaderFooterViewHolder(LayoutInflater.from(context).inflate(R.layout.cursor_adapter_header_footer_view, parent, false));
default:
return onCreateItemViewHolder(parent, viewType);
}
}
@@ -154,7 +176,11 @@ public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHold
@SuppressWarnings("unchecked")
@Override
public final void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (!isHeaderPosition(position) && !isFooterPosition(position)) {
if (isHeaderPosition(position)) {
((HeaderFooterViewHolder) viewHolder).bind(header);
} else if (isFooterPosition(position)) {
((HeaderFooterViewHolder) viewHolder).bind(footer);
} else {
if (isFastAccessPosition(position)) onBindFastAccessItemViewHolder((VH)viewHolder, position);
else onBindItemViewHolder((VH)viewHolder, getCursorAtPositionOrThrow(position));
}

View File

@@ -165,12 +165,14 @@ public class GroupDatabase extends Database {
public List<String> getGroupNamesContainingMember(RecipientId recipientId) {
SQLiteDatabase database = databaseHelper.getReadableDatabase();
String table = TABLE_NAME + " INNER JOIN " + ThreadDatabase.TABLE_NAME + " ON " + TABLE_NAME + "." + RECIPIENT_ID + " = " + ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.RECIPIENT_ID;
List<String> groupNames = new LinkedList<>();
String[] projection = new String[]{TITLE, MEMBERS};
String query = MEMBERS + " LIKE ?";
String[] args = new String[]{"%" + recipientId.serialize() + "%"};
String orderBy = ThreadDatabase.TABLE_NAME + "." + ThreadDatabase.DATE + " DESC";
try (Cursor cursor = database.query(TABLE_NAME, projection, query, args, null, null, null)) {
try (Cursor cursor = database.query(table, projection, query, args, null, null, orderBy)) {
while (cursor != null && cursor.moveToNext()) {
List<String> members = Util.split(cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)), ",");

View File

@@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
public abstract class MessagingDatabase extends Database implements MmsSmsColumns {
@@ -72,6 +73,36 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
return getMessageCountForRecipientsAndType(getOutgoingSecureMessageClause());
}
final int getSecureMessageCount(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] projection = new String[] {"COUNT(*)"};
String query = getSecureMessageClause() + "AND " + MmsSmsColumns.THREAD_ID + " = ?";
String[] args = new String[]{String.valueOf(threadId)};
try (Cursor cursor = db.query(getTableName(), projection, query, args, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
return 0;
}
}
}
final int getOutgoingSecureMessageCount(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] projection = new String[] {"COUNT(*)"};
String query = getOutgoingSecureMessageClause() + "AND " + MmsSmsColumns.THREAD_ID + " = ? AND" + "(" + getTypeField() + " & " + Types.GROUP_QUIT_BIT + " = 0)";
String[] args = new String[]{String.valueOf(threadId)};
try (Cursor cursor = db.query(getTableName(), projection, query, args, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
return 0;
}
}
}
private int getMessageCountForRecipientsAndType(String typeClause) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
@@ -96,6 +127,14 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
return "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND (" + getTypeField() + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")";
}
private String getSecureMessageClause() {
String isSent = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE;
String isReceived = "(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_INBOX_TYPE;
String isSecure = "(" + getTypeField() + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")";
return String.format(Locale.ENGLISH, "(%s OR %s) AND %s", isSent, isReceived, isSecure);
}
public void setReactionsSeen(long threadId) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
@@ -432,14 +471,20 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
public static class MarkedMessageInfo {
private final long threadId;
private final SyncMessageId syncMessageId;
private final ExpirationInfo expirationInfo;
public MarkedMessageInfo(SyncMessageId syncMessageId, ExpirationInfo expirationInfo) {
public MarkedMessageInfo(long threadId, SyncMessageId syncMessageId, ExpirationInfo expirationInfo) {
this.threadId = threadId;
this.syncMessageId = syncMessageId;
this.expirationInfo = expirationInfo;
}
public long getThreadId() {
return threadId;
}
public SyncMessageId getSyncMessageId() {
return syncMessageId;
}

View File

@@ -20,11 +20,12 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.google.android.mms.pdu_alt.NotificationInd;
@@ -81,7 +82,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import static org.thoughtcrime.securesms.contactshare.Contact.Avatar;
@@ -244,6 +244,42 @@ public class MmsDatabase extends MessagingDatabase {
return MESSAGE_BOX;
}
public boolean isGroupQuitMessage(long messageId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] columns = new String[]{ID};
String query = ID + " = ? AND " + MESSAGE_BOX + " & ?";
long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_QUIT_BIT;
String[] args = new String[]{String.valueOf(messageId), String.valueOf(type)};
try (Cursor cursor = db.query(TABLE_NAME, columns, query, args, null, null, null, null)) {
if (cursor.getCount() == 1) {
return true;
}
}
return false;
}
public long getLatestGroupQuitTimestamp(long threadId, long quitTimeBarrier) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] columns = new String[]{DATE_SENT};
String query = THREAD_ID + " = ? AND " + MESSAGE_BOX + " & ? AND " + DATE_SENT + " < ?";
long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_QUIT_BIT;
String[] args = new String[]{String.valueOf(threadId), String.valueOf(type), String.valueOf(quitTimeBarrier)};
String orderBy = DATE_SENT + " DESC";
String limit = "1";
try (Cursor cursor = db.query(TABLE_NAME, columns, query, args, null, null, orderBy, limit)) {
if (cursor.moveToFirst()) {
return cursor.getLong(cursor.getColumnIndex(DATE_SENT));
}
}
return -1;
}
public int getMessageCountForThread(long threadId) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = null;
@@ -533,14 +569,20 @@ public class MmsDatabase extends MessagingDatabase {
database.beginTransaction();
try {
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID}, where, arguments, null, null, null);
while(cursor != null && cursor.moveToNext()) {
if (Types.isSecureType(cursor.getLong(3))) {
SyncMessageId syncMessageId = new SyncMessageId(RecipientId.from(cursor.getLong(1)), cursor.getLong(2));
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), true);
if (Types.isSecureType(cursor.getLong(cursor.getColumnIndex(MESSAGE_BOX)))) {
long threadId = cursor.getLong(cursor.getColumnIndex(THREAD_ID));
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndex(RECIPIENT_ID)));
long dateSent = cursor.getLong(cursor.getColumnIndex(DATE_SENT));
long messageId = cursor.getLong(cursor.getColumnIndex(ID));
long expiresIn = cursor.getLong(cursor.getColumnIndex(EXPIRES_IN));
long expireStarted = cursor.getLong(cursor.getColumnIndex(EXPIRE_STARTED));
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
ExpirationInfo expirationInfo = new ExpirationInfo(messageId, expiresIn, expireStarted, true);
result.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
result.add(new MarkedMessageInfo(threadId, syncMessageId, expirationInfo));
}
}

View File

@@ -22,6 +22,8 @@ import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteQueryBuilder;
@@ -30,8 +32,10 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.Pair;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MmsSmsDatabase extends Database {
@@ -84,6 +88,32 @@ public class MmsSmsDatabase extends Database {
super(context, databaseHelper);
}
public @Nullable RecipientId getRecipientIdForLatestAdd(long threadId) {
long lastQuitChecked = System.currentTimeMillis();
Pair<RecipientId, Long> pair;
do {
pair = getRecipientIdForLatestAdd(threadId, lastQuitChecked);
if (pair.first() != null) {
return pair.first();
} else {
lastQuitChecked = pair.second();
}
} while (pair.second() != -1L);
return null;
}
private @NonNull Pair<RecipientId, Long> getRecipientIdForLatestAdd(long threadId, long lastQuitChecked) {
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
long latestQuit = mmsDatabase.getLatestGroupQuitTimestamp(threadId, lastQuitChecked);
RecipientId id = smsDatabase.getOldestGroupUpdateSender(threadId, latestQuit);
return new Pair<>(id, latestQuit);
}
public @Nullable MessageRecord getMessageFor(long timestamp, RecipientId author) {
MmsSmsDatabase db = DatabaseFactory.getMmsSmsDatabase(context);
@@ -166,6 +196,28 @@ public class MmsSmsDatabase extends Database {
}
}
public int getSecureConversationCount(long threadId) {
if (threadId == -1) {
return 0;
}
int count = DatabaseFactory.getSmsDatabase(context).getSecureMessageCount(threadId);
count += DatabaseFactory.getMmsDatabase(context).getSecureMessageCount(threadId);
return count;
}
public int getOutgoingSecureConversationCount(long threadId) {
if (threadId == -1L) {
return 0;
}
int count = DatabaseFactory.getSmsDatabase(context).getOutgoingSecureMessageCount(threadId);
count += DatabaseFactory.getMmsDatabase(context).getOutgoingSecureMessageCount(threadId);
return count;
}
public int getConversationCount(long threadId) {
int count = DatabaseFactory.getSmsDatabase(context).getMessageCountForThread(threadId);
count += DatabaseFactory.getMmsDatabase(context).getMessageCountForThread(threadId);
@@ -194,6 +246,13 @@ public class MmsSmsDatabase extends Database {
return count;
}
public long getThreadForMessageId(long messageId) {
long id = DatabaseFactory.getSmsDatabase(context).getThreadIdForMessage(messageId);
if (id == -1) return DatabaseFactory.getMmsDatabase(context).getThreadIdForMessage(messageId);
else return id;
}
public void incrementDeliveryReceiptCount(SyncMessageId syncMessageId, long timestamp) {
DatabaseFactory.getSmsDatabase(context).incrementReceiptCount(syncMessageId, true, false);
DatabaseFactory.getMmsDatabase(context).incrementReceiptCount(syncMessageId, timestamp, true, false);

View File

@@ -20,10 +20,12 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.annimon.stream.Stream;
import net.sqlcipher.database.SQLiteDatabase;
@@ -45,7 +47,6 @@ import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.libsignal.util.guava.Optional;
import java.io.IOException;
@@ -55,7 +56,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Database for storage of SMS messages.
@@ -162,6 +162,24 @@ public class SmsDatabase extends MessagingDatabase {
notifyConversationListeners(threadId);
}
public @Nullable RecipientId getOldestGroupUpdateSender(long threadId, long minimumDateReceived) {
SQLiteDatabase db = databaseHelper.getReadableDatabase();
String[] columns = new String[]{RECIPIENT_ID};
String query = THREAD_ID + " = ? AND " + TYPE + " & ? AND " + DATE_RECEIVED + " >= ?";
long type = Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT | Types.GROUP_UPDATE_BIT | Types.BASE_INBOX_TYPE;
String[] args = new String[]{String.valueOf(threadId), String.valueOf(type), String.valueOf(minimumDateReceived)};
String limit = "1";
try (Cursor cursor = db.query(TABLE_NAME, columns, query, args, null, null, limit)) {
if (cursor.moveToFirst()) {
return RecipientId.from(cursor.getLong(cursor.getColumnIndex(RECIPIENT_ID)));
}
}
return null;
}
public long getThreadIdForMessage(long id) {
String sql = "SELECT " + THREAD_ID + " FROM " + TABLE_NAME + " WHERE " + ID + " = ?";
String[] sqlArgs = new String[] {id+""};
@@ -446,14 +464,20 @@ public class SmsDatabase extends MessagingDatabase {
database.beginTransaction();
try {
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED}, where, arguments, null, null, null);
cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID}, where, arguments, null, null, null);
while (cursor != null && cursor.moveToNext()) {
if (Types.isSecureType(cursor.getLong(3))) {
SyncMessageId syncMessageId = new SyncMessageId(RecipientId.from(cursor.getLong(1)), cursor.getLong(2));
ExpirationInfo expirationInfo = new ExpirationInfo(cursor.getLong(0), cursor.getLong(4), cursor.getLong(5), false);
if (Types.isSecureType(cursor.getLong(cursor.getColumnIndex(TYPE)))) {
long threadId = cursor.getLong(cursor.getColumnIndex(THREAD_ID));
RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndex(RECIPIENT_ID)));
long dateSent = cursor.getLong(cursor.getColumnIndex(DATE_SENT));
long messageId = cursor.getLong(cursor.getColumnIndex(ID));
long expiresIn = cursor.getLong(cursor.getColumnIndex(EXPIRES_IN));
long expireStarted = cursor.getLong(cursor.getColumnIndex(EXPIRE_STARTED));
SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent);
ExpirationInfo expirationInfo = new ExpirationInfo(messageId, expiresIn, expireStarted, false);
results.add(new MarkedMessageInfo(syncMessageId, expirationInfo));
results.add(new MarkedMessageInfo(threadId, syncMessageId, expirationInfo));
}
}

View File

@@ -44,6 +44,7 @@ import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -704,13 +705,30 @@ public class ThreadDatabase extends Database {
}
private @Nullable Extra getExtrasFor(MessageRecord record) {
boolean messageRequestAccepted = RecipientUtil.isThreadMessageRequestAccepted(context, record.getThreadId());
RecipientId threadRecipientId = getRecipientIdForThreadId(record.getThreadId());
if (!messageRequestAccepted && threadRecipientId != null) {
boolean isPushGroup = Recipient.resolved(threadRecipientId).isPushGroup();
if (isPushGroup) {
RecipientId recipientId = DatabaseFactory.getMmsSmsDatabase(context).getRecipientIdForLatestAdd(record.getThreadId());
if (recipientId != null) {
return Extra.forGroupMessageRequest(recipientId);
}
}
return Extra.forMessageRequest();
}
if (record.isMms() && ((MmsMessageRecord) record).isViewOnce()) {
return Extra.forRevealableMessage();
return Extra.forRevealable();
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getStickerSlide() != null) {
return Extra.forSticker();
} else if (record.isMms() && ((MmsMessageRecord) record).getSlideDeck().getSlides().size() > 1) {
return Extra.forAlbum();
}
return null;
}
@@ -829,28 +847,41 @@ public class ThreadDatabase extends Database {
@JsonProperty private final boolean isRevealable;
@JsonProperty private final boolean isSticker;
@JsonProperty private final boolean isAlbum;
@JsonProperty private final boolean isMessageRequestAccepted;
@JsonProperty private final String groupAddedBy;
public Extra(@JsonProperty("isRevealable") boolean isRevealable,
@JsonProperty("isSticker") boolean isSticker,
@JsonProperty("isAlbum") boolean isAlbum)
@JsonProperty("isAlbum") boolean isAlbum,
@JsonProperty("isMessageRequestAccepted") boolean isMessageRequestAccepted,
@JsonProperty("groupAddedBy") String groupAddedBy)
{
this.isRevealable = isRevealable;
this.isSticker = isSticker;
this.isAlbum = isAlbum;
this.isRevealable = isRevealable;
this.isSticker = isSticker;
this.isAlbum = isAlbum;
this.isMessageRequestAccepted = isMessageRequestAccepted;
this.groupAddedBy = groupAddedBy;
}
public static @NonNull Extra forRevealableMessage() {
return new Extra(true, false, false);
public static @NonNull Extra forRevealable() {
return new Extra(true, false, false, true, null);
}
public static @NonNull Extra forSticker() {
return new Extra(false, true, false);
return new Extra(false, true, false, true, null);
}
public static @NonNull Extra forAlbum() {
return new Extra(false, false, true);
return new Extra(false, false, true, true, null);
}
public static @NonNull Extra forMessageRequest() {
return new Extra(false, false, false, false, null);
}
public static @NonNull Extra forGroupMessageRequest(RecipientId recipientId) {
return new Extra(false, false, false, false, recipientId.serialize());
}
public boolean isRevealable() {
return isRevealable;
@@ -863,5 +894,13 @@ public class ThreadDatabase extends Database {
public boolean isAlbum() {
return isAlbum;
}
public boolean isMessageRequestAccepted() {
return isMessageRequestAccepted;
}
public @Nullable String getGroupAddedBy() {
return groupAddedBy;
}
}
}

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.database.Cursor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.AbstractCursorLoader;
import org.whispersystems.libsignal.util.Pair;
@@ -13,6 +14,7 @@ public class ConversationLoader extends AbstractCursorLoader {
private int limit;
private long lastSeen;
private boolean hasSent;
private boolean isMessageRequestAccepted;
public ConversationLoader(Context context, long threadId, int offset, int limit, long lastSeen) {
super(context);
@@ -43,6 +45,10 @@ public class ConversationLoader extends AbstractCursorLoader {
return hasSent;
}
public boolean isMessageRequestAccepted() {
return isMessageRequestAccepted;
}
@Override
public Cursor getCursor() {
Pair<Long, Boolean> lastSeenAndHasSent = DatabaseFactory.getThreadDatabase(context).getLastSeenAndHasSent(threadId);
@@ -53,6 +59,8 @@ public class ConversationLoader extends AbstractCursorLoader {
this.lastSeen = lastSeenAndHasSent.first();
}
this.isMessageRequestAccepted = RecipientUtil.isThreadMessageRequestAccepted(context, threadId);
return DatabaseFactory.getMmsSmsDatabase(context).getConversation(threadId, offset, limit);
}
}

View File

@@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.database.MmsSmsColumns;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase.Extra;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.MediaUtil;
@@ -77,7 +78,11 @@ public class ThreadRecord extends DisplayRecord {
@Override
public SpannableString getDisplayBody(@NonNull Context context) {
if (isGroupUpdate()) {
if (getGroupAddedBy() != null) {
return emphasisAdded(context.getString(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));
@@ -181,4 +186,14 @@ public class ThreadRecord extends DisplayRecord {
public long getLastSeen() {
return lastSeen;
}
public @Nullable RecipientId getGroupAddedBy() {
if (extra != null && extra.getGroupAddedBy() != null) return RecipientId.from(extra.getGroupAddedBy());
else return null;
}
public boolean isMessageRequestAccepted() {
if (extra != null) return extra.isMessageRequestAccepted();
else return true;
}
}