From 6c3baf229c6a4ea7e655a9d3f08ee096b7280bf5 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 24 Mar 2022 14:09:39 -0300 Subject: [PATCH] Fix broadcast send when user sends to both story and non-story. --- .../mediasend/v2/MediaSelectionRepository.kt | 18 +++++--- .../securesms/sms/MessageSender.java | 41 +++++++++++++++++-- .../securesms/sms/OutgoingStoryMessage.kt | 8 ++++ .../stories/viewer/page/StoryPost.kt | 4 +- .../viewer/page/StoryViewerPageRepository.kt | 18 +++++++- .../text/StoryTextPostPreviewFragment.kt | 2 +- .../viewer/text/StoryTextPostViewModel.kt | 13 ++++-- 7 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingStoryMessage.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt index 7ac5d60cf..a41ae5172 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionRepository.kt @@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.scribbles.ImageEditorFragment import org.thoughtcrime.securesms.sms.MessageSender import org.thoughtcrime.securesms.sms.MessageSender.PreUploadResult +import org.thoughtcrime.securesms.sms.OutgoingStoryMessage import org.thoughtcrime.securesms.util.MessageUtil import java.util.Collections import java.util.concurrent.TimeUnit @@ -254,12 +255,19 @@ class MediaSelectionRepository(context: Context) { } } - storyMessages.forEach { (preUploadResult, messages) -> - MessageSender.sendMediaBroadcast(context, messages, Collections.singleton(preUploadResult)) - } - if (broadcastMessages.isNotEmpty()) { - MessageSender.sendMediaBroadcast(context, broadcastMessages, preUploadResults) + MessageSender.sendMediaBroadcast( + context, + broadcastMessages, + preUploadResults, + storyMessages.flatMap { (preUploadResult, messages) -> + messages.map { OutgoingStoryMessage(it, preUploadResult) } + } + ) + } else { + storyMessages.forEach { (preUploadResult, messages) -> + MessageSender.sendMediaBroadcast(context, messages, Collections.singleton(preUploadResult), Collections.emptyList()) + } } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java index 4ad4f928e..76eb994c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java @@ -204,7 +204,11 @@ public class MessageSender { } } - public static void sendMediaBroadcast(@NonNull Context context, @NonNull List messages, @NonNull Collection preUploadResults) { + public static void sendMediaBroadcast(@NonNull Context context, + @NonNull List messages, + @NonNull Collection preUploadResults, + @NonNull List storyMessages) + { Log.i(TAG, "Sending media broadcast to " + Stream.of(messages).map(m -> m.getRecipient().getId()).toList()); Preconditions.checkArgument(messages.size() > 0, "No messages!"); Preconditions.checkArgument(Stream.of(messages).allMatch(m -> m.getAttachments().isEmpty()), "Messages can't have attachments! They should be pre-uploaded."); @@ -230,12 +234,13 @@ public class MessageSender { attachmentDatabase.updateMessageId(preUploadAttachmentIds, primaryMessageId, primaryMessage.getStoryType().isStory()); messageIds.add(primaryMessageId); + List preUploadAttachments = Stream.of(preUploadAttachmentIds) + .map(attachmentDatabase::getAttachment) + .toList(); + if (messages.size() > 0) { List secondaryMessages = messages.subList(1, messages.size()); List> attachmentCopies = new ArrayList<>(); - List preUploadAttachments = Stream.of(preUploadAttachmentIds) - .map(attachmentDatabase::getAttachment) - .toList(); for (int i = 0; i < preUploadAttachmentIds.size(); i++) { attachmentCopies.add(new ArrayList<>(messages.size())); @@ -266,6 +271,34 @@ public class MessageSender { } } + for (final OutgoingStoryMessage storyMessage : storyMessages) { + OutgoingSecureMediaMessage message = storyMessage.getOutgoingSecureMediaMessage(); + + if (!message.getStoryType().isStory()) { + throw new AssertionError("Only story messages can be sent via this method."); + } + + long allocatedThreadId = threadDatabase.getOrCreateThreadIdFor(message.getRecipient(), message.getDistributionType()); + long messageId = mmsDatabase.insertMessageOutbox(storyMessage.getOutgoingSecureMediaMessage(), allocatedThreadId, false, null); + Optional preUploadAttachment = preUploadAttachments.stream() + .filter(a -> a.getAttachmentId().equals(storyMessage.getPreUploadResult().getAttachmentId())) + .findFirst(); + + if (!preUploadAttachment.isPresent()) { + Log.w(TAG, "Dropping story message without pre-upload attachment."); + mmsDatabase.markAsSentFailed(messageId); + } else { + AttachmentId attachmentCopyId = attachmentDatabase.insertAttachmentForPreUpload(preUploadAttachment.get()).getAttachmentId(); + attachmentDatabase.updateMessageId(Collections.singletonList(attachmentCopyId), messageId, true); + messageIds.add(messageId); + messages.add(storyMessage.getOutgoingSecureMediaMessage()); + + Job copyJob = new AttachmentCopyJob(storyMessage.getPreUploadResult().getAttachmentId(), Collections.singletonList(attachmentCopyId)); + jobManager.add(copyJob, preUploadJobIds); + messageDependsOnIds.add(copyJob.getId()); + } + } + for (int i = 0; i < messageIds.size(); i++) { long messageId = messageIds.get(i); OutgoingSecureMediaMessage message = messages.get(i); diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingStoryMessage.kt b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingStoryMessage.kt new file mode 100644 index 000000000..59dbb8931 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/OutgoingStoryMessage.kt @@ -0,0 +1,8 @@ +package org.thoughtcrime.securesms.sms + +import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage + +class OutgoingStoryMessage( + val outgoingSecureMediaMessage: OutgoingSecureMediaMessage, + val preUploadResult: MessageSender.PreUploadResult +) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryPost.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryPost.kt index 7ccf94566..2fa83c8b2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryPost.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryPost.kt @@ -28,8 +28,8 @@ class StoryPost( override fun isVideo(): Boolean = MediaUtil.isVideo(attachment) } - class TextContent(uri: Uri, val recordId: Long) : Content(uri) { - override val transferState: Int = AttachmentDatabase.TRANSFER_PROGRESS_DONE + class TextContent(uri: Uri, val recordId: Long, hasBody: Boolean) : Content(uri) { + override val transferState: Int = if (hasBody) AttachmentDatabase.TRANSFER_PROGRESS_DONE else AttachmentDatabase.TRANSFER_PROGRESS_FAILED override fun isVideo(): Boolean = false } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt index d58e23f51..bb760b38e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageRepository.kt @@ -14,12 +14,14 @@ import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.MessageId import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord +import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost import org.thoughtcrime.securesms.dependencies.ApplicationDependencies import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob import org.thoughtcrime.securesms.jobs.MultiDeviceViewedUpdateJob import org.thoughtcrime.securesms.jobs.SendViewedReceiptJob import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId +import org.thoughtcrime.securesms.util.Base64 class StoryViewerPageRepository(context: Context) { @@ -175,7 +177,8 @@ class StoryViewerPageRepository(context: Context) { return if (record.storyType.isTextStory || record.slideDeck.asAttachments().isEmpty()) { StoryPost.Content.TextContent( uri = Uri.parse("story_text_post://${record.id}"), - recordId = record.id + recordId = record.id, + hasBody = canParseToTextStory(record.body) ) } else { StoryPost.Content.AttachmentContent( @@ -183,4 +186,17 @@ class StoryViewerPageRepository(context: Context) { ) } } + + private fun canParseToTextStory(body: String): Boolean { + return if (body.isNotEmpty()) { + try { + StoryTextPost.parseFrom(Base64.decode(body)) + return true + } catch (e: Exception) { + false + } + } else { + false + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostPreviewFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostPreviewFragment.kt index eb737ce8f..2ebc2340b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostPreviewFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostPreviewFragment.kt @@ -66,10 +66,10 @@ class StoryTextPostPreviewFragment : Fragment(R.layout.stories_text_post_preview } else { storyTextPostView.setLinkPreviewClickListener(null) } - requireActivity().supportStartPostponedEnterTransition() loadPreview(storyTextThumb, storyTextPostView) } StoryTextPostState.LoadState.FAILED -> { + requireActivity().supportStartPostponedEnterTransition() requireListener().mediaNotAvailable() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostViewModel.kt index 21b50fec1..02f895a92 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/text/StoryTextPostViewModel.kt @@ -19,12 +19,19 @@ class StoryTextPostViewModel(recordId: Long, repository: StoryTextPostRepository init { disposables += repository.getRecord(recordId) + .map { + if (it.body.isNotEmpty()) { + StoryTextPost.parseFrom(Base64.decode(it.body)) to it.linkPreviews.firstOrNull() + } else { + throw Exception("Text post message body is empty.") + } + } .subscribeBy( - onSuccess = { record -> + onSuccess = { (post, previews) -> store.update { state -> state.copy( - storyTextPost = StoryTextPost.parseFrom(Base64.decode(record.body)), - linkPreview = record.linkPreviews.firstOrNull(), + storyTextPost = post, + linkPreview = previews, loadState = StoryTextPostState.LoadState.LOADED ) }