Fix several over-the-wire story issues.
Co-authored-by: Rashad Sookram <rashad@signal.org>
This commit is contained in:
parent
e701e4bff0
commit
d5fd424b95
12 changed files with 98 additions and 58 deletions
|
@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.Quote;
|
import org.thoughtcrime.securesms.database.model.Quote;
|
||||||
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
import org.thoughtcrime.securesms.database.model.StoryViewState;
|
||||||
|
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||||
|
@ -813,7 +814,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
public int getMessageCountForThread(long threadId) {
|
public int getMessageCountForThread(long threadId) {
|
||||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||||
|
|
||||||
String query = THREAD_ID + " = ? AND " + IS_STORY + " = ? AND " + PARENT_STORY_ID + " = ?";
|
String query = THREAD_ID + " = ? AND " + IS_STORY + " = ? AND " + PARENT_STORY_ID + " <= ?";
|
||||||
String[] args = SqlUtil.buildArgs(threadId, 0, 0);
|
String[] args = SqlUtil.buildArgs(threadId, 0, 0);
|
||||||
|
|
||||||
try (Cursor cursor = db.query(TABLE_NAME, COUNT, query, args, null, null, null)) {
|
try (Cursor cursor = db.query(TABLE_NAME, COUNT, query, args, null, null, null)) {
|
||||||
|
@ -829,7 +830,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
public int getMessageCountForThread(long threadId, long beforeTime) {
|
public int getMessageCountForThread(long threadId, long beforeTime) {
|
||||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||||
|
|
||||||
String query = THREAD_ID + " = ? AND " + DATE_RECEIVED + " < ? AND " + IS_STORY + " = ? AND " + PARENT_STORY_ID + " = ?";
|
String query = THREAD_ID + " = ? AND " + DATE_RECEIVED + " < ? AND " + IS_STORY + " = ? AND " + PARENT_STORY_ID + " <= ?";
|
||||||
String[] args = SqlUtil.buildArgs(threadId, beforeTime, 0, 0);
|
String[] args = SqlUtil.buildArgs(threadId, beforeTime, 0, 0);
|
||||||
|
|
||||||
try (Cursor cursor = db.query(TABLE_NAME, COUNT, query, args, null, null, null)) {
|
try (Cursor cursor = db.query(TABLE_NAME, COUNT, query, args, null, null, null)) {
|
||||||
|
@ -1207,20 +1208,20 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
@Override
|
@Override
|
||||||
public List<MarkedMessageInfo> setMessagesReadSince(long threadId, long sinceTimestamp) {
|
public List<MarkedMessageInfo> setMessagesReadSince(long threadId, long sinceTimestamp) {
|
||||||
if (sinceTimestamp == -1) {
|
if (sinceTimestamp == -1) {
|
||||||
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " = 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND (" + getOutgoingTypeClause() + ")))", new String[] {String.valueOf(threadId)});
|
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " <= 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND (" + getOutgoingTypeClause() + ")))", new String[] {String.valueOf(threadId)});
|
||||||
} else {
|
} else {
|
||||||
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " = 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND ( " + getOutgoingTypeClause() + " ))) AND " + DATE_RECEIVED + " <= ?", new String[]{String.valueOf(threadId), String.valueOf(sinceTimestamp)});
|
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " <= 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND ( " + getOutgoingTypeClause() + " ))) AND " + DATE_RECEIVED + " <= ?", new String[]{String.valueOf(threadId), String.valueOf(sinceTimestamp)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MarkedMessageInfo> setEntireThreadRead(long threadId) {
|
public List<MarkedMessageInfo> setEntireThreadRead(long threadId) {
|
||||||
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " = 0", new String[] {String.valueOf(threadId)});
|
return setMessagesRead(THREAD_ID + " = ? AND " + IS_STORY + " = 0 AND " + PARENT_STORY_ID + " <= 0", new String[] {String.valueOf(threadId)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<MarkedMessageInfo> setAllMessagesRead() {
|
public List<MarkedMessageInfo> setAllMessagesRead() {
|
||||||
return setMessagesRead(IS_STORY+ " = 0 AND " + PARENT_STORY_ID + " = 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND (" + getOutgoingTypeClause() + ")))", null);
|
return setMessagesRead(IS_STORY+ " = 0 AND " + PARENT_STORY_ID + " <= 0 AND (" + READ + " = 0 OR (" + REACTIONS_UNREAD + " = 1 AND (" + getOutgoingTypeClause() + ")))", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MarkedMessageInfo> setMessagesRead(String where, String[] arguments) {
|
private List<MarkedMessageInfo> setMessagesRead(String where, String[] arguments) {
|
||||||
|
@ -1419,7 +1420,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
|
||||||
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
|
||||||
boolean isStory = CursorUtil.requireBoolean(cursor, IS_STORY);
|
boolean isStory = CursorUtil.requireBoolean(cursor, IS_STORY);
|
||||||
MessageId parentStoryId = MessageId.fromNullable(CursorUtil.requireLong(cursor, PARENT_STORY_ID), true);
|
ParentStoryId parentStoryId = ParentStoryId.deserialize(CursorUtil.requireLong(cursor, PARENT_STORY_ID));
|
||||||
|
|
||||||
long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID));
|
long quoteId = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_ID));
|
||||||
long quoteAuthor = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
|
long quoteAuthor = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
|
||||||
|
@ -1590,7 +1591,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
|
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
|
||||||
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
|
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0);
|
||||||
contentValues.put(IS_STORY, retrieved.isStory() ? 1 : 0);
|
contentValues.put(IS_STORY, retrieved.isStory() ? 1 : 0);
|
||||||
contentValues.put(PARENT_STORY_ID, retrieved.getParentStoryId() != null ? retrieved.getParentStoryId().getId() : 0);
|
contentValues.put(PARENT_STORY_ID, retrieved.getParentStoryId() != null ? retrieved.getParentStoryId().serialize() : 0);
|
||||||
contentValues.put(READ, retrieved.isExpirationUpdate() ? 1 : 0);
|
contentValues.put(READ, retrieved.isExpirationUpdate() ? 1 : 0);
|
||||||
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
contentValues.put(UNIDENTIFIED, retrieved.isUnidentified());
|
||||||
contentValues.put(SERVER_GUID, retrieved.getServerGuid());
|
contentValues.put(SERVER_GUID, retrieved.getServerGuid());
|
||||||
|
@ -1785,7 +1786,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum());
|
contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum());
|
||||||
contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
|
contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
|
||||||
contentValues.put(IS_STORY, message.isStory() ? 1 : 0);
|
contentValues.put(IS_STORY, message.isStory() ? 1 : 0);
|
||||||
contentValues.put(PARENT_STORY_ID, message.getParentStoryId() != null ? message.getParentStoryId().getId() : 0);
|
contentValues.put(PARENT_STORY_ID, message.getParentStoryId() != null ? message.getParentStoryId().serialize() : 0);
|
||||||
|
|
||||||
if (message.getRecipient().isSelf() && hasAudioAttachment(message.getAttachments())) {
|
if (message.getRecipient().isSelf() && hasAudioAttachment(message.getAttachments())) {
|
||||||
contentValues.put(VIEWED_RECEIPT_COUNT, 1L);
|
contentValues.put(VIEWED_RECEIPT_COUNT, 1L);
|
||||||
|
|
|
@ -118,7 +118,7 @@ public class MmsSmsDatabase extends Database {
|
||||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ", " + SmsDatabase.Types.CHANGE_NUMBER_TYPE + ", " + SmsDatabase.Types.BOOST_REQUEST_TYPE + ") AND " + SmsDatabase.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " +
|
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsDatabase.TYPE + " NOT IN (" + SmsDatabase.Types.PROFILE_CHANGE_TYPE + ", " + SmsDatabase.Types.GV1_MIGRATION_TYPE + ", " + SmsDatabase.Types.CHANGE_NUMBER_TYPE + ", " + SmsDatabase.Types.BOOST_REQUEST_TYPE + ") AND " + SmsDatabase.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " +
|
||||||
"UNION ALL " +
|
"UNION ALL " +
|
||||||
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsDatabase.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsDatabase.TABLE_NAME + " " +
|
"SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsDatabase.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsDatabase.TABLE_NAME + " " +
|
||||||
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsDatabase.MESSAGE_BOX + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsDatabase.PARENT_STORY_ID + " = 0 " +
|
"WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsDatabase.MESSAGE_BOX + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsDatabase.PARENT_STORY_ID + " <= 0 " +
|
||||||
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
|
"ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " +
|
||||||
"LIMIT 1";
|
"LIMIT 1";
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ public class MmsSmsDatabase extends Database {
|
||||||
public Cursor getConversation(long threadId, long offset, long limit) {
|
public Cursor getConversation(long threadId, long offset, long limit) {
|
||||||
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
|
||||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsDatabase.PARENT_STORY_ID + " = 0";
|
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsDatabase.PARENT_STORY_ID + " <= 0";
|
||||||
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
|
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
|
||||||
String query = buildQuery(PROJECTION, selection, order, limitStr, false);
|
String query = buildQuery(PROJECTION, selection, order, limitStr, false);
|
||||||
|
|
||||||
|
@ -264,19 +264,16 @@ public class MmsSmsDatabase extends Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||||
String selection = MmsSmsColumns.NOTIFIED + " = 0 AND (" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1" + (stickyQuery.length() > 0 ? " OR (" + stickyQuery.toString() + ")" : "") + ")";
|
String selection = MmsSmsColumns.NOTIFIED + " = 0 AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsDatabase.PARENT_STORY_ID + " <= 0 AND (" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1" + (stickyQuery.length() > 0 ? " OR (" + stickyQuery.toString() + ")" : "") + ")";
|
||||||
|
|
||||||
return queryTables(PROJECTION, selection, order, null);
|
return queryTables(PROJECTION, selection, order, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getUnreadCount(long threadId) {
|
public int getUnreadCount(long threadId) {
|
||||||
String selection = MmsSmsColumns.READ + " = 0 AND " + MmsSmsColumns.THREAD_ID + " = " + threadId;
|
String selection = MmsSmsColumns.READ + " = 0 AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsDatabase.PARENT_STORY_ID + " <= 0";
|
||||||
Cursor cursor = queryTables(PROJECTION, selection, null, null);
|
|
||||||
|
|
||||||
try {
|
try (Cursor cursor = queryTables(PROJECTION, selection, null, null)) {
|
||||||
return cursor != null ? cursor.getCount() : 0;
|
return cursor != null ? cursor.getCount() : 0;
|
||||||
} finally {
|
|
||||||
if (cursor != null) cursor.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package org.thoughtcrime.securesms.database.model
|
||||||
|
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract representation of a message id for a story.
|
||||||
|
*
|
||||||
|
* At the database layer, the sign of the id is dependant on whether a reply is meant for
|
||||||
|
* a group thread or a direct reply. This class facilitates that, while still allowing for
|
||||||
|
* normal behaviour elsewhere.
|
||||||
|
*/
|
||||||
|
sealed class ParentStoryId(protected val id: Long) {
|
||||||
|
abstract fun serialize(): Long
|
||||||
|
|
||||||
|
fun asMessageId(): MessageId = MessageId(abs(id), true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parent story who's child should be displayed in a group reply thread.
|
||||||
|
*/
|
||||||
|
class GroupReply(id: Long) : ParentStoryId(id) {
|
||||||
|
override fun serialize(): Long = abs(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A parent story who's child should be displayed in a 1:1 conversation.
|
||||||
|
*/
|
||||||
|
class DirectReply(id: Long) : ParentStoryId(id) {
|
||||||
|
override fun serialize(): Long = -abs(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Takes a long stored in the database and converts it to an appropriate subclass of ParentStoryId.
|
||||||
|
* If the passed value is 0L, null is returned.
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun deserialize(id: Long): ParentStoryId? {
|
||||||
|
return when {
|
||||||
|
id > 0L -> GroupReply(id)
|
||||||
|
id < 0L -> DirectReply(id)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -222,7 +222,6 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
|
|
||||||
GroupId.Push groupId = groupRecipient.requireGroupId().requirePush();
|
GroupId.Push groupId = groupRecipient.requireGroupId().requirePush();
|
||||||
Optional<byte[]> profileKey = getProfileKey(groupRecipient);
|
Optional<byte[]> profileKey = getProfileKey(groupRecipient);
|
||||||
Optional<Quote> quote = getQuoteFor(message);
|
|
||||||
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
List<SignalServicePreview> previews = getPreviewsFor(message);
|
List<SignalServicePreview> previews = getPreviewsFor(message);
|
||||||
|
@ -290,7 +289,6 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
.withViewOnce(message.isViewOnce())
|
.withViewOnce(message.isViewOnce())
|
||||||
.asExpirationUpdate(message.isExpirationUpdate())
|
.asExpirationUpdate(message.isExpirationUpdate())
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
.withQuote(quote.orNull())
|
|
||||||
.withSticker(sticker.orNull())
|
.withSticker(sticker.orNull())
|
||||||
.withSharedContacts(sharedContacts)
|
.withSharedContacts(sharedContacts)
|
||||||
.withPreviews(previews)
|
.withPreviews(previews)
|
||||||
|
@ -298,7 +296,7 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
|
|
||||||
if (message.getParentStoryId() != null) {
|
if (message.getParentStoryId() != null) {
|
||||||
try {
|
try {
|
||||||
MessageRecord storyRecord = SignalDatabase.mms().getMessageRecord(message.getParentStoryId().getId());
|
MessageRecord storyRecord = SignalDatabase.mms().getMessageRecord(message.getParentStoryId().asMessageId().getId());
|
||||||
Recipient recipient = storyRecord.isOutgoing() ? Recipient.self() : storyRecord.getIndividualRecipient();
|
Recipient recipient = storyRecord.isOutgoing() ? Recipient.self() : storyRecord.getIndividualRecipient();
|
||||||
|
|
||||||
groupMessageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(recipient.requireServiceId(), storyRecord.getDateSent()));
|
groupMessageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(recipient.requireServiceId(), storyRecord.getDateSent()));
|
||||||
|
@ -307,6 +305,8 @@ public final class PushGroupSendJob extends PushSendJob {
|
||||||
// TODO [stories] check what should happen in this case
|
// TODO [stories] check what should happen in this case
|
||||||
throw new UndeliverableMessageException(e);
|
throw new UndeliverableMessageException(e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
groupMessageBuilder.withQuote(getQuoteFor(message).orNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, JobLogger.format(this, "Beginning message send."));
|
Log.i(TAG, JobLogger.format(this, "Beginning message send."));
|
||||||
|
|
|
@ -208,7 +208,6 @@ public class PushMediaSendJob extends PushSendJob {
|
||||||
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
|
||||||
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(attachments);
|
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(attachments);
|
||||||
Optional<byte[]> profileKey = getProfileKey(messageRecipient);
|
Optional<byte[]> profileKey = getProfileKey(messageRecipient);
|
||||||
Optional<SignalServiceDataMessage.Quote> quote = getQuoteFor(message);
|
|
||||||
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
|
||||||
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
List<SharedContact> sharedContacts = getSharedContactsFor(message);
|
||||||
List<SignalServicePreview> previews = getPreviewsFor(message);
|
List<SignalServicePreview> previews = getPreviewsFor(message);
|
||||||
|
@ -219,7 +218,6 @@ public class PushMediaSendJob extends PushSendJob {
|
||||||
.withExpiration((int)(message.getExpiresIn() / 1000))
|
.withExpiration((int)(message.getExpiresIn() / 1000))
|
||||||
.withViewOnce(message.isViewOnce())
|
.withViewOnce(message.isViewOnce())
|
||||||
.withProfileKey(profileKey.orNull())
|
.withProfileKey(profileKey.orNull())
|
||||||
.withQuote(quote.orNull())
|
|
||||||
.withSticker(sticker.orNull())
|
.withSticker(sticker.orNull())
|
||||||
.withSharedContacts(sharedContacts)
|
.withSharedContacts(sharedContacts)
|
||||||
.withPreviews(previews)
|
.withPreviews(previews)
|
||||||
|
@ -227,13 +225,15 @@ public class PushMediaSendJob extends PushSendJob {
|
||||||
|
|
||||||
if (message.getParentStoryId() != null) {
|
if (message.getParentStoryId() != null) {
|
||||||
try {
|
try {
|
||||||
MessageRecord storyRecord = SignalDatabase.mms().getMessageRecord(message.getParentStoryId().getId());
|
MessageRecord storyRecord = SignalDatabase.mms().getMessageRecord(message.getParentStoryId().asMessageId().getId());
|
||||||
mediaMessageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(address.getServiceId(), storyRecord.getDateSent()));
|
mediaMessageBuilder.withStoryContext(new SignalServiceDataMessage.StoryContext(address.getServiceId(), storyRecord.getDateSent()));
|
||||||
} catch (NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
// The story has probably expired
|
// The story has probably expired
|
||||||
// TODO [stories] check what should happen in this case
|
// TODO [stories] check what should happen in this case
|
||||||
throw new UndeliverableMessageException(e);
|
throw new UndeliverableMessageException(e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mediaMessageBuilder.withQuote(getQuoteFor(message).orNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
SignalServiceDataMessage mediaMessage = mediaMessageBuilder.build();
|
SignalServiceDataMessage mediaMessage = mediaMessageBuilder.build();
|
||||||
|
|
|
@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.database.model.MessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageLogEntry;
|
import org.thoughtcrime.securesms.database.model.MessageLogEntry;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||||
import org.thoughtcrime.securesms.database.model.PendingRetryReceiptModel;
|
import org.thoughtcrime.securesms.database.model.PendingRetryReceiptModel;
|
||||||
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
import org.thoughtcrime.securesms.database.model.ReactionRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
import org.thoughtcrime.securesms.database.model.StickerRecord;
|
||||||
|
@ -1376,11 +1377,20 @@ public final class MessageContentProcessor {
|
||||||
database.beginTransaction();
|
database.beginTransaction();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO [stories] check if this works for group stories
|
|
||||||
RecipientId storyAuthorRecipient = RecipientId.from(storyContext.getAuthorServiceId(), null);
|
RecipientId storyAuthorRecipient = RecipientId.from(storyContext.getAuthorServiceId(), null);
|
||||||
MessageId storyId;
|
ParentStoryId parentStoryId;
|
||||||
|
QuoteModel quoteModel = null;
|
||||||
try {
|
try {
|
||||||
storyId = database.getStoryId(storyAuthorRecipient, storyContext.getSentTimestamp());
|
MessageId storyMessageId = database.getStoryId(storyAuthorRecipient, storyContext.getSentTimestamp());
|
||||||
|
|
||||||
|
if (message.getGroupContext().isPresent()) {
|
||||||
|
parentStoryId = new ParentStoryId.GroupReply(storyMessageId.getId());
|
||||||
|
} else {
|
||||||
|
MmsMessageRecord story = (MmsMessageRecord) database.getMessageRecord(storyMessageId.getId());
|
||||||
|
|
||||||
|
parentStoryId = new ParentStoryId.DirectReply(storyMessageId.getId());
|
||||||
|
quoteModel = new QuoteModel(storyContext.getSentTimestamp(), storyAuthorRecipient, "", false, story.getSlideDeck().asAttachments(), Collections.emptyList());
|
||||||
|
}
|
||||||
} catch (NoSuchMessageException e) {
|
} catch (NoSuchMessageException e) {
|
||||||
warn(content.getTimestamp(), "Couldn't find story for reply.", e);
|
warn(content.getTimestamp(), "Couldn't find story for reply.", e);
|
||||||
return;
|
return;
|
||||||
|
@ -1391,7 +1401,7 @@ public final class MessageContentProcessor {
|
||||||
content.getServerReceivedTimestamp(),
|
content.getServerReceivedTimestamp(),
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
false,
|
false,
|
||||||
storyId,
|
parentStoryId,
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
|
@ -1400,7 +1410,7 @@ public final class MessageContentProcessor {
|
||||||
message.getBody(),
|
message.getBody(),
|
||||||
Optional.fromNullable(GroupUtil.getGroupContextIfPresent(content)),
|
Optional.fromNullable(GroupUtil.getGroupContextIfPresent(content)),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.fromNullable(quoteModel),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
Optional.absent(),
|
Optional.absent(),
|
||||||
|
|
|
@ -4,7 +4,7 @@ import org.thoughtcrime.securesms.attachments.Attachment
|
||||||
import org.thoughtcrime.securesms.attachments.PointerAttachment
|
import org.thoughtcrime.securesms.attachments.PointerAttachment
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact
|
import org.thoughtcrime.securesms.contactshare.Contact
|
||||||
import org.thoughtcrime.securesms.database.model.Mention
|
import org.thoughtcrime.securesms.database.model.Mention
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId
|
import org.thoughtcrime.securesms.database.model.ParentStoryId
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
|
||||||
import org.thoughtcrime.securesms.groups.GroupId
|
import org.thoughtcrime.securesms.groups.GroupId
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||||
|
@ -20,7 +20,7 @@ class IncomingMediaMessage(
|
||||||
val body: String? = null,
|
val body: String? = null,
|
||||||
val isPushMessage: Boolean = false,
|
val isPushMessage: Boolean = false,
|
||||||
val isStory: Boolean = false,
|
val isStory: Boolean = false,
|
||||||
val parentStoryId: MessageId? = null,
|
val parentStoryId: ParentStoryId? = null,
|
||||||
val sentTimeMillis: Long,
|
val sentTimeMillis: Long,
|
||||||
val serverTimeMillis: Long,
|
val serverTimeMillis: Long,
|
||||||
val receivedTimeMillis: Long,
|
val receivedTimeMillis: Long,
|
||||||
|
@ -84,7 +84,7 @@ class IncomingMediaMessage(
|
||||||
serverTimeMillis: Long,
|
serverTimeMillis: Long,
|
||||||
receivedTimeMillis: Long,
|
receivedTimeMillis: Long,
|
||||||
isStory: Boolean,
|
isStory: Boolean,
|
||||||
parentStoryId: MessageId?,
|
parentStoryId: ParentStoryId?,
|
||||||
subscriptionId: Int,
|
subscriptionId: Int,
|
||||||
expiresIn: Long,
|
expiresIn: Long,
|
||||||
expirationUpdate: Boolean,
|
expirationUpdate: Boolean,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.contactshare.Contact;
|
||||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
import org.thoughtcrime.securesms.database.model.Mention;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public class OutgoingMediaMessage {
|
||||||
private final boolean viewOnce;
|
private final boolean viewOnce;
|
||||||
private final QuoteModel outgoingQuote;
|
private final QuoteModel outgoingQuote;
|
||||||
private final boolean isStory;
|
private final boolean isStory;
|
||||||
private final MessageId parentStoryId;
|
private final ParentStoryId parentStoryId;
|
||||||
|
|
||||||
private final Set<NetworkFailure> networkFailures = new HashSet<>();
|
private final Set<NetworkFailure> networkFailures = new HashSet<>();
|
||||||
private final Set<IdentityKeyMismatch> identityKeyMismatches = new HashSet<>();
|
private final Set<IdentityKeyMismatch> identityKeyMismatches = new HashSet<>();
|
||||||
|
@ -48,7 +48,7 @@ public class OutgoingMediaMessage {
|
||||||
boolean viewOnce,
|
boolean viewOnce,
|
||||||
int distributionType,
|
int distributionType,
|
||||||
boolean isStory,
|
boolean isStory,
|
||||||
@Nullable MessageId parentStoryId,
|
@Nullable ParentStoryId parentStoryId,
|
||||||
@Nullable QuoteModel outgoingQuote,
|
@Nullable QuoteModel outgoingQuote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> linkPreviews,
|
@NonNull List<LinkPreview> linkPreviews,
|
||||||
|
@ -84,7 +84,7 @@ public class OutgoingMediaMessage {
|
||||||
boolean viewOnce,
|
boolean viewOnce,
|
||||||
int distributionType,
|
int distributionType,
|
||||||
boolean isStory,
|
boolean isStory,
|
||||||
@Nullable MessageId parentStoryId,
|
@Nullable ParentStoryId parentStoryId,
|
||||||
@Nullable QuoteModel outgoingQuote,
|
@Nullable QuoteModel outgoingQuote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> linkPreviews,
|
@NonNull List<LinkPreview> linkPreviews,
|
||||||
|
@ -197,7 +197,7 @@ public class OutgoingMediaMessage {
|
||||||
return isStory;
|
return isStory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable MessageId getParentStoryId() {
|
public @Nullable ParentStoryId getParentStoryId() {
|
||||||
return parentStoryId;
|
return parentStoryId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import androidx.annotation.Nullable;
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||||
import org.thoughtcrime.securesms.database.model.Mention;
|
import org.thoughtcrime.securesms.database.model.Mention;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
import org.thoughtcrime.securesms.database.model.ParentStoryId;
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
|
||||||
long expiresIn,
|
long expiresIn,
|
||||||
boolean viewOnce,
|
boolean viewOnce,
|
||||||
boolean isStory,
|
boolean isStory,
|
||||||
@Nullable MessageId parentStoryId,
|
@Nullable ParentStoryId parentStoryId,
|
||||||
@Nullable QuoteModel quote,
|
@Nullable QuoteModel quote,
|
||||||
@NonNull List<Contact> contacts,
|
@NonNull List<Contact> contacts,
|
||||||
@NonNull List<LinkPreview> previews,
|
@NonNull List<LinkPreview> previews,
|
||||||
|
|
|
@ -8,7 +8,6 @@ import io.reactivex.rxjava3.core.Completable
|
||||||
import io.reactivex.rxjava3.core.Observable
|
import io.reactivex.rxjava3.core.Observable
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import io.reactivex.rxjava3.subjects.BehaviorSubject
|
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
import io.reactivex.rxjava3.subjects.Subject
|
import io.reactivex.rxjava3.subjects.Subject
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
|
@ -26,26 +25,13 @@ class StoryViewerPageViewModel(
|
||||||
|
|
||||||
private val store = Store(StoryViewerPageState())
|
private val store = Store(StoryViewerPageState())
|
||||||
private val disposables = CompositeDisposable()
|
private val disposables = CompositeDisposable()
|
||||||
private val storyViewerDialogSubject: Subject<Optional<StoryViewerDialog>> = BehaviorSubject.createDefault(Optional.empty())
|
private val storyViewerDialogSubject: Subject<Optional<StoryViewerDialog>> = PublishSubject.create()
|
||||||
private val dismissSubject = PublishSubject.create<StoryViewerDialog.Type>()
|
|
||||||
|
|
||||||
private val storyViewerPlaybackStore = Store(StoryViewerPlaybackState())
|
private val storyViewerPlaybackStore = Store(StoryViewerPlaybackState())
|
||||||
|
|
||||||
val storyViewerPlaybackState: LiveData<StoryViewerPlaybackState> = storyViewerPlaybackStore.stateLiveData
|
val storyViewerPlaybackState: LiveData<StoryViewerPlaybackState> = storyViewerPlaybackStore.stateLiveData
|
||||||
|
|
||||||
val groupDirectReplyObservable: Observable<Optional<StoryViewerDialog>> = Observable.combineLatest(storyViewerDialogSubject, dismissSubject) { sheet, dismissed ->
|
val groupDirectReplyObservable: Observable<Optional<StoryViewerDialog>> = storyViewerDialogSubject
|
||||||
if (sheet.isPresent && sheet.get().type != dismissed) {
|
|
||||||
sheet
|
|
||||||
} else {
|
|
||||||
Optional.empty()
|
|
||||||
}
|
|
||||||
}.distinctUntilChanged { previous, current ->
|
|
||||||
if (current.isPresent) {
|
|
||||||
previous == current
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val state: LiveData<StoryViewerPageState> = store.stateLiveData
|
val state: LiveData<StoryViewerPageState> = store.stateLiveData
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
|
import org.thoughtcrime.securesms.database.model.ParentStoryId
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
||||||
import org.thoughtcrime.securesms.mms.QuoteModel
|
import org.thoughtcrime.securesms.mms.QuoteModel
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
@ -53,7 +54,7 @@ class StoryDirectReplyRepository {
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
null,
|
ParentStoryId.DirectReply(storyId),
|
||||||
QuoteModel(message.dateSent, quoteAuthor.id, "", false, message.slideDeck.asAttachments(), null),
|
QuoteModel(message.dateSent, quoteAuthor.id, "", false, message.slideDeck.asAttachments(), null),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
|
|
|
@ -5,7 +5,7 @@ import io.reactivex.rxjava3.core.Completable
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.Mention
|
import org.thoughtcrime.securesms.database.model.Mention
|
||||||
import org.thoughtcrime.securesms.database.model.MessageId
|
import org.thoughtcrime.securesms.database.model.ParentStoryId
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ object StoryGroupReplySender {
|
||||||
false,
|
false,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
MessageId.fromNullable(message.id, true),
|
ParentStoryId.GroupReply(message.id),
|
||||||
null,
|
null,
|
||||||
emptyList(),
|
emptyList(),
|
||||||
emptyList(),
|
emptyList(),
|
||||||
|
|
Loading…
Add table
Reference in a new issue