Fix several over-the-wire story issues.

Co-authored-by: Rashad Sookram <rashad@signal.org>
This commit is contained in:
Alex Hart 2022-02-28 12:37:37 -04:00
parent e701e4bff0
commit d5fd424b95
12 changed files with 98 additions and 58 deletions

View file

@ -54,6 +54,7 @@ import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.Quote;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
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.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
@ -813,7 +814,7 @@ public class MmsDatabase extends MessageDatabase {
public int getMessageCountForThread(long threadId) {
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);
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) {
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);
try (Cursor cursor = db.query(TABLE_NAME, COUNT, query, args, null, null, null)) {
@ -1207,20 +1208,20 @@ public class MmsDatabase extends MessageDatabase {
@Override
public List<MarkedMessageInfo> setMessagesReadSince(long threadId, long sinceTimestamp) {
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 {
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
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
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) {
@ -1419,7 +1420,7 @@ public class MmsDatabase extends MessageDatabase {
String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.MISMATCHED_IDENTITIES));
String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.NETWORK_FAILURE));
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 quoteAuthor = cursor.getLong(cursor.getColumnIndexOrThrow(QUOTE_AUTHOR));
@ -1590,7 +1591,7 @@ public class MmsDatabase extends MessageDatabase {
contentValues.put(EXPIRES_IN, retrieved.getExpiresIn());
contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 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(UNIDENTIFIED, retrieved.isUnidentified());
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(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1));
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())) {
contentValues.put(VIEWED_RECEIPT_COUNT, 1L);

View file

@ -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 + " " +
"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 + " " +
"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 " +
"LIMIT 1";
@ -202,7 +202,7 @@ public class MmsSmsDatabase extends Database {
public Cursor getConversation(long threadId, long offset, long limit) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
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 query = buildQuery(PROJECTION, selection, order, limitStr, false);
@ -264,19 +264,16 @@ public class MmsSmsDatabase extends Database {
}
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);
}
public int getUnreadCount(long threadId) {
String selection = MmsSmsColumns.READ + " = 0 AND " + MmsSmsColumns.THREAD_ID + " = " + threadId;
Cursor cursor = queryTables(PROJECTION, selection, null, null);
String selection = MmsSmsColumns.READ + " = 0 AND " + MmsDatabase.IS_STORY + " = 0 AND " + MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsDatabase.PARENT_STORY_ID + " <= 0";
try {
try (Cursor cursor = queryTables(PROJECTION, selection, null, null)) {
return cursor != null ? cursor.getCount() : 0;
} finally {
if (cursor != null) cursor.close();
}
}

View file

@ -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
}
}
}
}

View file

@ -222,7 +222,6 @@ public final class PushGroupSendJob extends PushSendJob {
GroupId.Push groupId = groupRecipient.requireGroupId().requirePush();
Optional<byte[]> profileKey = getProfileKey(groupRecipient);
Optional<Quote> quote = getQuoteFor(message);
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
List<SharedContact> sharedContacts = getSharedContactsFor(message);
List<SignalServicePreview> previews = getPreviewsFor(message);
@ -290,7 +289,6 @@ public final class PushGroupSendJob extends PushSendJob {
.withViewOnce(message.isViewOnce())
.asExpirationUpdate(message.isExpirationUpdate())
.withProfileKey(profileKey.orNull())
.withQuote(quote.orNull())
.withSticker(sticker.orNull())
.withSharedContacts(sharedContacts)
.withPreviews(previews)
@ -298,7 +296,7 @@ public final class PushGroupSendJob extends PushSendJob {
if (message.getParentStoryId() != null) {
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();
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
throw new UndeliverableMessageException(e);
}
} else {
groupMessageBuilder.withQuote(getQuoteFor(message).orNull());
}
Log.i(TAG, JobLogger.format(this, "Beginning message send."));

View file

@ -208,7 +208,6 @@ public class PushMediaSendJob extends PushSendJob {
List<Attachment> attachments = Stream.of(message.getAttachments()).filterNot(Attachment::isSticker).toList();
List<SignalServiceAttachment> serviceAttachments = getAttachmentPointersFor(attachments);
Optional<byte[]> profileKey = getProfileKey(messageRecipient);
Optional<SignalServiceDataMessage.Quote> quote = getQuoteFor(message);
Optional<SignalServiceDataMessage.Sticker> sticker = getStickerFor(message);
List<SharedContact> sharedContacts = getSharedContactsFor(message);
List<SignalServicePreview> previews = getPreviewsFor(message);
@ -219,7 +218,6 @@ public class PushMediaSendJob extends PushSendJob {
.withExpiration((int)(message.getExpiresIn() / 1000))
.withViewOnce(message.isViewOnce())
.withProfileKey(profileKey.orNull())
.withQuote(quote.orNull())
.withSticker(sticker.orNull())
.withSharedContacts(sharedContacts)
.withPreviews(previews)
@ -227,13 +225,15 @@ public class PushMediaSendJob extends PushSendJob {
if (message.getParentStoryId() != null) {
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()));
} catch (NoSuchMessageException e) {
// The story has probably expired
// TODO [stories] check what should happen in this case
throw new UndeliverableMessageException(e);
}
} else {
mediaMessageBuilder.withQuote(getQuoteFor(message).orNull());
}
SignalServiceDataMessage mediaMessage = mediaMessageBuilder.build();

View file

@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.database.model.MessageId;
import org.thoughtcrime.securesms.database.model.MessageLogEntry;
import org.thoughtcrime.securesms.database.model.MessageRecord;
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.ReactionRecord;
import org.thoughtcrime.securesms.database.model.StickerRecord;
@ -1376,11 +1377,20 @@ public final class MessageContentProcessor {
database.beginTransaction();
try {
// TODO [stories] check if this works for group stories
RecipientId storyAuthorRecipient = RecipientId.from(storyContext.getAuthorServiceId(), null);
MessageId storyId;
RecipientId storyAuthorRecipient = RecipientId.from(storyContext.getAuthorServiceId(), null);
ParentStoryId parentStoryId;
QuoteModel quoteModel = null;
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) {
warn(content.getTimestamp(), "Couldn't find story for reply.", e);
return;
@ -1391,7 +1401,7 @@ public final class MessageContentProcessor {
content.getServerReceivedTimestamp(),
System.currentTimeMillis(),
false,
storyId,
parentStoryId,
-1,
0,
false,
@ -1400,7 +1410,7 @@ public final class MessageContentProcessor {
message.getBody(),
Optional.fromNullable(GroupUtil.getGroupContextIfPresent(content)),
Optional.absent(),
Optional.absent(),
Optional.fromNullable(quoteModel),
Optional.absent(),
Optional.absent(),
Optional.absent(),

View file

@ -4,7 +4,7 @@ import org.thoughtcrime.securesms.attachments.Attachment
import org.thoughtcrime.securesms.attachments.PointerAttachment
import org.thoughtcrime.securesms.contactshare.Contact
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.groups.GroupId
import org.thoughtcrime.securesms.linkpreview.LinkPreview
@ -20,7 +20,7 @@ class IncomingMediaMessage(
val body: String? = null,
val isPushMessage: Boolean = false,
val isStory: Boolean = false,
val parentStoryId: MessageId? = null,
val parentStoryId: ParentStoryId? = null,
val sentTimeMillis: Long,
val serverTimeMillis: Long,
val receivedTimeMillis: Long,
@ -84,7 +84,7 @@ class IncomingMediaMessage(
serverTimeMillis: Long,
receivedTimeMillis: Long,
isStory: Boolean,
parentStoryId: MessageId?,
parentStoryId: ParentStoryId?,
subscriptionId: Int,
expiresIn: Long,
expirationUpdate: Boolean,

View file

@ -10,7 +10,7 @@ import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
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.recipients.Recipient;
@ -31,7 +31,7 @@ public class OutgoingMediaMessage {
private final boolean viewOnce;
private final QuoteModel outgoingQuote;
private final boolean isStory;
private final MessageId parentStoryId;
private final ParentStoryId parentStoryId;
private final Set<NetworkFailure> networkFailures = new HashSet<>();
private final Set<IdentityKeyMismatch> identityKeyMismatches = new HashSet<>();
@ -48,7 +48,7 @@ public class OutgoingMediaMessage {
boolean viewOnce,
int distributionType,
boolean isStory,
@Nullable MessageId parentStoryId,
@Nullable ParentStoryId parentStoryId,
@Nullable QuoteModel outgoingQuote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
@ -84,7 +84,7 @@ public class OutgoingMediaMessage {
boolean viewOnce,
int distributionType,
boolean isStory,
@Nullable MessageId parentStoryId,
@Nullable ParentStoryId parentStoryId,
@Nullable QuoteModel outgoingQuote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> linkPreviews,
@ -197,7 +197,7 @@ public class OutgoingMediaMessage {
return isStory;
}
public @Nullable MessageId getParentStoryId() {
public @Nullable ParentStoryId getParentStoryId() {
return parentStoryId;
}

View file

@ -6,7 +6,7 @@ import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.contactshare.Contact;
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.recipients.Recipient;
@ -23,7 +23,7 @@ public class OutgoingSecureMediaMessage extends OutgoingMediaMessage {
long expiresIn,
boolean viewOnce,
boolean isStory,
@Nullable MessageId parentStoryId,
@Nullable ParentStoryId parentStoryId,
@Nullable QuoteModel quote,
@NonNull List<Contact> contacts,
@NonNull List<LinkPreview> previews,

View file

@ -8,7 +8,6 @@ import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.subjects.BehaviorSubject
import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject
import org.thoughtcrime.securesms.recipients.RecipientId
@ -26,26 +25,13 @@ class StoryViewerPageViewModel(
private val store = Store(StoryViewerPageState())
private val disposables = CompositeDisposable()
private val storyViewerDialogSubject: Subject<Optional<StoryViewerDialog>> = BehaviorSubject.createDefault(Optional.empty())
private val dismissSubject = PublishSubject.create<StoryViewerDialog.Type>()
private val storyViewerDialogSubject: Subject<Optional<StoryViewerDialog>> = PublishSubject.create()
private val storyViewerPlaybackStore = Store(StoryViewerPlaybackState())
val storyViewerPlaybackState: LiveData<StoryViewerPlaybackState> = storyViewerPlaybackStore.stateLiveData
val groupDirectReplyObservable: Observable<Optional<StoryViewerDialog>> = Observable.combineLatest(storyViewerDialogSubject, dismissSubject) { sheet, dismissed ->
if (sheet.isPresent && sheet.get().type != dismissed) {
sheet
} else {
Optional.empty()
}
}.distinctUntilChanged { previous, current ->
if (current.isPresent) {
previous == current
} else {
false
}
}
val groupDirectReplyObservable: Observable<Optional<StoryViewerDialog>> = storyViewerDialogSubject
val state: LiveData<StoryViewerPageState> = store.stateLiveData

View file

@ -7,6 +7,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
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.QuoteModel
import org.thoughtcrime.securesms.recipients.Recipient
@ -53,7 +54,7 @@ class StoryDirectReplyRepository {
false,
0,
false,
null,
ParentStoryId.DirectReply(storyId),
QuoteModel(message.dateSent, quoteAuthor.id, "", false, message.slideDeck.asAttachments(), null),
emptyList(),
emptyList(),

View file

@ -5,7 +5,7 @@ import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.SignalDatabase
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.sms.MessageSender
@ -31,7 +31,7 @@ object StoryGroupReplySender {
false,
0,
false,
MessageId.fromNullable(message.id, true),
ParentStoryId.GroupReply(message.id),
null,
emptyList(),
emptyList(),