Add text formatting send and receive support for conversations.

This commit is contained in:
Cody Henthorne
2023-01-25 10:31:36 -05:00
committed by Greyson Parrelli
parent aa2075c78f
commit cc490f4b73
73 changed files with 1664 additions and 516 deletions

View File

@@ -1,13 +1,18 @@
package org.thoughtcrime.securesms.mediasend
import android.content.Intent
import android.os.Parcel
import android.os.Parcelable
import kotlinx.parcelize.Parceler
import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.TypeParceler
import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.sms.MessageSender.PreUploadResult
import org.thoughtcrime.securesms.util.ParcelUtil
/**
* A class that lets us nicely format data that we'll send back to [ConversationActivity].
@@ -21,6 +26,7 @@ class MediaSendActivityResult(
val messageSendType: MessageSendType,
val isViewOnce: Boolean,
val mentions: List<Mention>,
@TypeParceler<BodyRangeList?, BodyRangeListParceler>() val bodyRanges: BodyRangeList?,
val storyType: StoryType
) : Parcelable {
@@ -40,3 +46,18 @@ class MediaSendActivityResult(
}
}
}
object BodyRangeListParceler : Parceler<BodyRangeList?> {
override fun create(parcel: Parcel): BodyRangeList? {
val data: ByteArray? = ParcelUtil.readByteArray(parcel)
return if (data != null) {
BodyRangeList.parseFrom(data)
} else {
null
}
}
override fun BodyRangeList?.write(parcel: Parcel, flags: Int) {
ParcelUtil.writeByteArray(parcel, this?.toByteArray())
}
}

View File

@@ -17,6 +17,7 @@ import org.thoughtcrime.securesms.database.AttachmentTable.TransformProperties
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.Mention
import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.BodyRangeList
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.keyvalue.StorySend
import org.thoughtcrime.securesms.mediasend.CompositeMediaTransform
@@ -76,6 +77,7 @@ class MediaSelectionRepository(context: Context) {
singleContact: ContactSearchKey.RecipientSearchKey?,
contacts: List<ContactSearchKey.RecipientSearchKey>,
mentions: List<Mention>,
bodyRanges: BodyRangeList?,
sendType: MessageSendType
): Maybe<MediaSendActivityResult> {
if (isSms && contacts.isNotEmpty()) {
@@ -89,9 +91,10 @@ class MediaSelectionRepository(context: Context) {
val isSendingToStories = singleContact?.isStory == true || contacts.any { it.isStory }
val sentMediaQuality = if (isSendingToStories) SentMediaQuality.STANDARD else quality
return Maybe.create<MediaSendActivityResult> { emitter ->
return Maybe.create { emitter ->
val trimmedBody: String = if (isViewOnce) "" else getTruncatedBody(message?.toString()?.trim()) ?: ""
val trimmedMentions: List<Mention> = if (isViewOnce) emptyList() else mentions
val trimmedBodyRanges: BodyRangeList? = if (isViewOnce) null else bodyRanges
val modelsToTransform: Map<Media, MediaTransform> = buildModelsToTransform(selectedMedia, stateMap, sentMediaQuality)
val oldToNewMediaMap: Map<Media, Media> = MediaRepository.transformMediaSync(context, selectedMedia, modelsToTransform)
val updatedMedia = oldToNewMediaMap.values.toList()
@@ -119,6 +122,7 @@ class MediaSelectionRepository(context: Context) {
messageSendType = sendType,
isViewOnce = isViewOnce,
mentions = trimmedMentions,
bodyRanges = trimmedBodyRanges,
storyType = StoryType.NONE
)
)
@@ -154,7 +158,7 @@ class MediaSelectionRepository(context: Context) {
uploadRepository.updateDisplayOrder(updatedMedia)
uploadRepository.getPreUploadResults { uploadResults ->
if (contacts.isNotEmpty()) {
sendMessages(contacts, splitBody, uploadResults, trimmedMentions, isViewOnce, clippedVideosForStories)
sendMessages(contacts, splitBody, uploadResults, trimmedMentions, trimmedBodyRanges, isViewOnce, clippedVideosForStories)
uploadRepository.deleteAbandonedAttachments()
emitter.onComplete()
} else if (uploadResults.isNotEmpty()) {
@@ -166,6 +170,7 @@ class MediaSelectionRepository(context: Context) {
messageSendType = sendType,
isViewOnce = isViewOnce,
mentions = trimmedMentions,
bodyRanges = trimmedBodyRanges,
storyType = storyType
)
)
@@ -179,6 +184,7 @@ class MediaSelectionRepository(context: Context) {
messageSendType = sendType,
isViewOnce = isViewOnce,
mentions = trimmedMentions,
bodyRanges = trimmedBodyRanges,
storyType = storyType
)
)
@@ -256,6 +262,7 @@ class MediaSelectionRepository(context: Context) {
body: String,
preUploadResults: Collection<PreUploadResult>,
mentions: List<Mention>,
bodyRanges: BodyRangeList?,
isViewOnce: Boolean,
storyClips: List<Media>
) {
@@ -287,6 +294,7 @@ class MediaSelectionRepository(context: Context) {
isViewOnce = isViewOnce,
storyType = storyType,
mentions = mentions,
bodyRanges = bodyRanges,
isSecure = true
)
@@ -317,6 +325,7 @@ class MediaSelectionRepository(context: Context) {
isViewOnce = isViewOnce,
storyType = storyType,
mentions = mentions,
bodyRanges = bodyRanges,
isSecure = true
)
)

View File

@@ -22,6 +22,7 @@ import org.signal.core.util.BreakIteratorCompat
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.conversation.MessageStyler
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.VideoEditorFragment
@@ -336,16 +337,17 @@ class MediaSelectionViewModel(
): Maybe<MediaSendActivityResult> {
return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet(), identityChangesSince).andThen(
repository.send(
store.state.selectedMedia,
store.state.editorStateMap,
store.state.quality,
store.state.message,
store.state.sendType.usesSmsTransport,
isViewOnceEnabled(),
destination.getRecipientSearchKey(),
selectedContacts.ifEmpty { destination.getRecipientSearchKeyList() },
MentionAnnotation.getMentionsFromAnnotations(store.state.message),
store.state.sendType
selectedMedia = store.state.selectedMedia,
stateMap = store.state.editorStateMap,
quality = store.state.quality,
message = store.state.message,
isSms = store.state.sendType.usesSmsTransport,
isViewOnce = isViewOnceEnabled(),
singleContact = destination.getRecipientSearchKey(),
contacts = selectedContacts.ifEmpty { destination.getRecipientSearchKeyList() },
mentions = MentionAnnotation.getMentionsFromAnnotations(store.state.message),
bodyRanges = MessageStyler.getStyling(store.state.message),
sendType = store.state.sendType
)
)
}