From 921c903190cd57b9ee8895c5fca55d0c7dcbb29b Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 5 Apr 2023 13:16:06 -0300 Subject: [PATCH] Allow forwarding of contacts. --- .../securesms/conversation/MenuState.java | 1 - .../forward/MultiselectForwardFragmentArgs.kt | 5 ++ .../messages/MessageContentProcessor.java | 3 +- .../securesms/mms/OutgoingMessage.kt | 6 ++- .../securesms/sharing/MultiShareArgs.java | 46 +++++++++++++------ .../securesms/sharing/MultiShareSender.java | 20 +++++--- 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java index 0cac6c9713..57f11a61dc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/MenuState.java @@ -135,7 +135,6 @@ final class MenuState { } boolean shouldShowForwardAction = !actionMessage && - !sharedContact && !viewOnce && !remoteDelete && !hasPendingMedia && diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt index 043a69f6f5..7967b9ea16 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardFragmentArgs.kt @@ -23,6 +23,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.sharing.MultiShareArgs import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.MediaUtil +import org.thoughtcrime.securesms.util.hasSharedContact import java.util.Optional import java.util.function.Consumer @@ -136,6 +137,10 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor( builder.asTextStory(mediaMessage?.storyType?.isTextStory ?: false) } + if (conversationMessage.messageRecord.hasSharedContact() && conversationMessage.multiselectCollection.isMediaSelected(selectedParts)) { + builder.withSharedContacts((conversationMessage.messageRecord as MmsMessageRecord).sharedContacts) + } + if (conversationMessage.messageRecord.isMms && conversationMessage.multiselectCollection.isMediaSelected(selectedParts)) { val mediaMessage: MmsMessageRecord = conversationMessage.messageRecord as MmsMessageRecord val isAlbum = mediaMessage.containsMediaSlide() && diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java index d476bf62d3..0229fde4c6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/MessageContentProcessor.java @@ -2647,7 +2647,8 @@ public class MessageContentProcessor { Collections.emptyList(), Collections.emptyList(), true, - bodyRanges); + bodyRanges, + Collections.emptyList()); messageId = SignalDatabase.messages().insertMessageOutbox(outgoingMessage, threadId, false, GroupReceiptTable.STATUS_UNKNOWN, null); database = SignalDatabase.messages(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt index ad1f22784b..51b1797ef6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/OutgoingMessage.kt @@ -120,7 +120,8 @@ data class OutgoingMessage( linkPreviews: List = emptyList(), mentions: List = emptyList(), isSecure: Boolean = false, - bodyRanges: BodyRangeList? = null + bodyRanges: BodyRangeList? = null, + contacts: List = emptyList() ) : this( recipient = recipient, body = buildMessage(slideDeck, body ?: ""), @@ -133,7 +134,8 @@ data class OutgoingMessage( linkPreviews = linkPreviews, mentions = mentions, isSecure = isSecure, - bodyRanges = bodyRanges + bodyRanges = bodyRanges, + sharedContacts = contacts ) fun withExpiry(expiresIn: Long): OutgoingMessage { diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java index 5f7a896fb4..3a5b846911 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareArgs.java @@ -14,6 +14,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import org.signal.core.util.BreakIteratorCompat; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey; +import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.database.model.Mention; import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList; import org.thoughtcrime.securesms.linkpreview.LinkPreview; @@ -23,6 +24,7 @@ import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.ParcelUtil; import org.thoughtcrime.securesms.util.Util; +import org.whispersystems.signalservice.api.messages.shared.SharedContact; import java.io.IOException; import java.util.ArrayList; @@ -50,6 +52,7 @@ public final class MultiShareArgs implements Parcelable { private final long expiresAt; private final boolean isTextStory; private final BodyRangeList bodyRanges; + private final List sharedContacts; private MultiShareArgs(@NonNull Builder builder) { contactSearchKeys = builder.contactSearchKeys; @@ -66,6 +69,7 @@ public final class MultiShareArgs implements Parcelable { expiresAt = builder.expiresAt; isTextStory = builder.isTextStory; bodyRanges = builder.bodyRanges; + sharedContacts = builder.sharedContacts == null ? new ArrayList<>() : new ArrayList<>(builder.sharedContacts); } protected MultiShareArgs(Parcel in) { @@ -104,6 +108,7 @@ public final class MultiShareArgs implements Parcelable { Log.w(TAG, "Invalid body range", e); } this.bodyRanges = bodyRanges; + sharedContacts = in.createTypedArrayList(Contact.CREATOR); } public Set getContactSearchKeys() { @@ -169,6 +174,10 @@ public final class MultiShareArgs implements Parcelable { return bodyRanges; } + public @NonNull List getSharedContacts() { + return sharedContacts; + } + public boolean isValidForStories() { if (isViewOnce()) { return false; @@ -269,6 +278,8 @@ public final class MultiShareArgs implements Parcelable { } else { ParcelUtil.writeByteArray(dest, null); } + + dest.writeTypedList(sharedContacts); } public Builder buildUpon() { @@ -288,7 +299,8 @@ public final class MultiShareArgs implements Parcelable { .withTimestamp(timestamp) .withExpiration(expiresAt) .asTextStory(isTextStory) - .withBodyRanges(bodyRanges); + .withBodyRanges(bodyRanges) + .withSharedContacts(sharedContacts); } private boolean requiresInterstitial() { @@ -303,19 +315,20 @@ public final class MultiShareArgs implements Parcelable { private final Set contactSearchKeys; - private List media; - private String draftText; - private StickerLocator stickerLocator; - private boolean borderless; - private Uri dataUri; - private String dataType; - private LinkPreview linkPreview; - private boolean viewOnce; - private List mentions; - private long timestamp; - private long expiresAt; - private boolean isTextStory; - private BodyRangeList bodyRanges; + private List media; + private String draftText; + private StickerLocator stickerLocator; + private boolean borderless; + private Uri dataUri; + private String dataType; + private LinkPreview linkPreview; + private boolean viewOnce; + private List mentions; + private long timestamp; + private long expiresAt; + private boolean isTextStory; + private BodyRangeList bodyRanges; + private List sharedContacts; public Builder() { this(Collections.emptySet()); @@ -390,6 +403,11 @@ public final class MultiShareArgs implements Parcelable { return this; } + public @NonNull Builder withSharedContacts(List sharedContacts) { + this.sharedContacts = new ArrayList<>(sharedContacts); + return this; + } + public @NonNull MultiShareArgs build() { return new MultiShareArgs(this); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java index b495e8007f..6c160421b8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sharing/MultiShareSender.java @@ -19,6 +19,7 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.attachments.UriAttachment; import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey; +import org.thoughtcrime.securesms.contactshare.Contact; import org.thoughtcrime.securesms.conversation.MessageSendType; import org.thoughtcrime.securesms.conversation.colors.ChatColors; import org.thoughtcrime.securesms.database.AttachmentTable; @@ -111,6 +112,7 @@ public final class MultiShareSender { boolean forceSms = recipient.isForceSmsSelection() && sendType.usesSmsTransport(); int subscriptionId = sendType.getSimSubscriptionIdOr(-1); long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds()); + List contacts = multiShareArgs.getSharedContacts(); boolean needsSplit = !sendType.usesSmsTransport() && message != null && message.length() > sendType.calculateCharacters(message).maxPrimaryMessageSize; @@ -122,7 +124,8 @@ public final class MultiShareSender { boolean hasPushMedia = hasMmsMedia || multiShareArgs.getLinkPreview() != null || !mentions.isEmpty() || - needsSplit; + needsSplit || + !contacts.isEmpty(); MultiShareTimestampProvider sentTimestamp = recipient.isDistributionList() ? distributionListSentTimestamps : MultiShareTimestampProvider.create(); boolean canSendAsTextStory = recipientSearchKey.isStory() && multiShareArgs.isValidForTextStoryGeneration(); @@ -145,7 +148,8 @@ public final class MultiShareSender { sentTimestamp, canSendAsTextStory, storiesBatch, - generatedTextStoryBackgroundColor); + generatedTextStoryBackgroundColor, + contacts); results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.SUCCESS)); } else if (recipientSearchKey.isStory()) { results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.INVALID_SHARE_TO_STORY)); @@ -213,7 +217,8 @@ public final class MultiShareSender { @NonNull MultiShareTimestampProvider sentTimestamps, boolean canSendAsTextStory, @NonNull List storiesToBatchSend, - @NonNull ChatColors generatedTextStoryBackgroundColor) + @NonNull ChatColors generatedTextStoryBackgroundColor, + @NonNull List contacts) { String body = multiShareArgs.getDraftText(); if (sendType.usesSignalTransport() && !forceSms && body != null) { @@ -251,7 +256,8 @@ public final class MultiShareSender { buildLinkPreviews(context, multiShareArgs.getLinkPreview()), Collections.emptyList(), false, - multiShareArgs.getBodyRanges()); + multiShareArgs.getBodyRanges(), + contacts); outgoingMessages.add(outgoingMessage); } else if (canSendAsTextStory) { @@ -288,7 +294,8 @@ public final class MultiShareSender { Collections.emptyList(), validatedMentions, false, - multiShareArgs.getBodyRanges()); + multiShareArgs.getBodyRanges(), + contacts); outgoingMessages.add(outgoingMessage); } @@ -305,7 +312,8 @@ public final class MultiShareSender { buildLinkPreviews(context, multiShareArgs.getLinkPreview()), validatedMentions, false, - multiShareArgs.getBodyRanges()); + multiShareArgs.getBodyRanges(), + contacts); outgoingMessages.add(outgoingMessage); }