diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java index 20f98ce88..36db28ced 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java @@ -189,6 +189,7 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns public abstract @NonNull Reader getAllStoriesFor(@NonNull RecipientId recipientId); public abstract @NonNull MessageId getStoryId(@NonNull RecipientId authorId, long sentTimestamp) throws NoSuchMessageException; public abstract int getNumberOfStoryReplies(long parentStoryId); + public abstract boolean containsStories(long threadId); public abstract boolean hasSelfReplyInStory(long parentStoryId); public abstract @NonNull Cursor getStoryReplies(long parentStoryId); public abstract long getUnreadStoryCount(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index 4eba8ed5f..6516f2e14 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -708,6 +708,18 @@ public class MmsDatabase extends MessageDatabase { } } + @Override + public boolean containsStories(long threadId) { + SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); + String[] columns = new String[]{"1"}; + String where = THREAD_ID_WHERE + " AND " + STORY_TYPE + " > 0"; + String[] whereArgs = SqlUtil.buildArgs(threadId); + + try (Cursor cursor = db.query(TABLE_NAME, columns, where, whereArgs, null, null, null, "1")) { + return cursor != null && cursor.moveToNext(); + } + } + @Override public boolean hasSelfReplyInStory(long parentStoryId) { SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 31d69b66a..95d1ce544 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -1424,6 +1424,11 @@ public class SmsDatabase extends MessageDatabase { throw new UnsupportedOperationException(); } + @Override + public boolean containsStories(long threadId) { + throw new UnsupportedOperationException(); + } + @Override public boolean hasSelfReplyInStory(long parentStoryId) { throw new UnsupportedOperationException(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java index e77ecdb66..bac0bfbce 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -1308,7 +1308,7 @@ public class ThreadDatabase extends Database { try { record = mmsSmsDatabase.getConversationSnippet(threadId); } catch (NoSuchMessageException e) { - if (allowDeletion) { + if (allowDeletion && !SignalDatabase.mms().containsStories(threadId)) { deleteConversation(threadId); } return true; diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java index 342673a45..a33cbda04 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushDistributionListSendJob.java @@ -10,13 +10,11 @@ import com.annimon.stream.Stream; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.database.GroupReceiptDatabase; -import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo; import org.thoughtcrime.securesms.database.MessageDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch; import org.thoughtcrime.securesms.database.documents.NetworkFailure; -import org.thoughtcrime.securesms.database.model.DistributionListId; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.jobmanager.Data; import org.thoughtcrime.securesms.jobmanager.Job; @@ -29,7 +27,7 @@ import org.thoughtcrime.securesms.mms.MmsException; import org.thoughtcrime.securesms.mms.OutgoingMediaMessage; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; -import org.thoughtcrime.securesms.recipients.RecipientUtil; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException; @@ -43,7 +41,6 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; /** * A job that lets us send a message to a distribution list. Currently the only supported message type is a story. @@ -148,7 +145,7 @@ public final class PushDistributionListSendJob extends PushSendJob { List target; if (!existingNetworkFailures.isEmpty()) target = Stream.of(existingNetworkFailures).map(nf -> nf.getRecipientId(context)).distinct().map(Recipient::resolved).toList(); - else target = Stream.of(getFullRecipients(listRecipient.requireDistributionListId(), messageId)).distinctBy(Recipient::getId).toList(); + else target = Stream.of(Stories.getRecipientsToSendTo(listRecipient.requireDistributionListId(), messageId)).distinctBy(Recipient::getId).toList(); List results = deliver(message, target); Log.i(TAG, JobLogger.format(this, "Finished send.")); @@ -189,23 +186,6 @@ public final class PushDistributionListSendJob extends PushSendJob { } } - private static List getFullRecipients(@NonNull DistributionListId distributionListId, long messageId) { - List destinations = SignalDatabase.groupReceipts().getGroupReceiptInfo(messageId); - - if (!destinations.isEmpty()) { - return RecipientUtil.getEligibleForSending(destinations.stream() - .map(GroupReceiptInfo::getRecipientId) - .map(Recipient::resolved) - .collect(Collectors.toList())); - } else { - return RecipientUtil.getEligibleForSending(SignalDatabase.distributionLists() - .getMembers(distributionListId) - .stream() - .map(Recipient::resolved) - .collect(Collectors.toList())); - } - } - public static class Factory implements Job.Factory { @Override public @NonNull PushDistributionListSendJob create(@NonNull Parameters parameters, @NonNull Data data) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java index a3ce1fa9b..cb746d990 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RemoteDeleteSendJob.java @@ -11,6 +11,7 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.database.MessageDatabase; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.SignalDatabase; +import org.thoughtcrime.securesms.database.model.DistributionListId; import org.thoughtcrime.securesms.database.model.MessageId; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.groups.GroupId; @@ -21,6 +22,7 @@ import org.thoughtcrime.securesms.net.NotPushRegisteredException; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientUtil; +import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.SetUtil; @@ -34,6 +36,7 @@ import org.whispersystems.signalservice.api.push.exceptions.ServerRejectedExcept import java.io.IOException; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class RemoteDeleteSendJob extends BaseJob { @@ -67,8 +70,18 @@ public class RemoteDeleteSendJob extends BaseJob { throw new AssertionError("We have a message, but couldn't find the thread!"); } - List recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() - : Stream.of(conversationRecipient.getId()).toList(); + List recipients; + if (conversationRecipient.isDistributionList()) { + DistributionListId distributionListId = conversationRecipient.requireDistributionListId(); + + recipients = Stories.getRecipientsToSendTo(distributionListId, messageId) + .stream() + .map(Recipient::getId) + .collect(Collectors.toList()); + } else { + recipients = conversationRecipient.isGroup() ? Stream.of(conversationRecipient.getParticipants()).map(Recipient::getId).toList() + : Stream.of(conversationRecipient.getId()).toList(); + } recipients.remove(Recipient.self().getId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt index 042570ea5..b89f073fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt @@ -5,11 +5,16 @@ import androidx.fragment.app.FragmentManager import io.reactivex.rxjava3.core.Completable import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.contacts.HeaderAction +import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo +import org.thoughtcrime.securesms.database.SignalDatabase +import org.thoughtcrime.securesms.database.model.DistributionListId import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet import org.thoughtcrime.securesms.mms.OutgoingMediaMessage import org.thoughtcrime.securesms.recipients.Recipient +import org.thoughtcrime.securesms.recipients.RecipientId +import org.thoughtcrime.securesms.recipients.RecipientUtil import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.FeatureFlags @@ -48,4 +53,17 @@ object Stories { } } } + + @JvmStatic + fun getRecipientsToSendTo(distributionListId: DistributionListId, messageId: Long): List { + val destinations: List = SignalDatabase.groupReceipts.getGroupReceiptInfo(messageId) + + val recipientIds: List = if (destinations.isNotEmpty()) { + destinations.map(GroupReceiptInfo::getRecipientId) + } else { + SignalDatabase.distributionLists.getMembers(distributionListId) + } + + return RecipientUtil.getEligibleForSending(recipientIds.map(Recipient::resolved)) + } }