Signal-iOS/SignalUI/ViewModels/ThreadUtil+SignalUI.swift
Evan Hahn 5696c50d7d Make some outgoing message params optional
We frequently send outgoing messages with some parameters, like "link
preview" or "quoted reply", empty.

This change lets those parameters be omitted (instead of explicitly
empty) for brevity.

This is a stylistic change and should have no user impact.

Tested this by sending a regular message, a message with a link preview,
and two messages with photos.
2022-06-23 12:53:05 +00:00

159 lines
6.9 KiB
Swift

//
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
import Foundation
import SignalMessaging
@objc
public extension ThreadUtil {
// MARK: - Durable Message Enqueue
@discardableResult
class func enqueueMessage(body messageBody: MessageBody?,
mediaAttachments: [SignalAttachment] = [],
thread: TSThread,
quotedReplyModel: OWSQuotedReplyModel? = nil,
linkPreviewDraft: OWSLinkPreviewDraft? = nil,
persistenceCompletionHandler persistenceCompletion: PersistenceCompletion? = nil,
transaction readTransaction: SDSAnyReadTransaction) -> TSOutgoingMessage {
AssertIsOnMainThread()
let outgoingMessagePreparer = OutgoingMessagePreparer(messageBody: messageBody,
mediaAttachments: mediaAttachments,
thread: thread,
quotedReplyModel: quotedReplyModel,
transaction: readTransaction)
let message: TSOutgoingMessage = outgoingMessagePreparer.unpreparedMessage
BenchManager.startEvent(
title: "Send Message Milestone: Sending (\(message.timestamp))",
eventId: "sendMessageSending-\(message.timestamp)",
logInProduction: true
)
BenchManager.startEvent(
title: "Send Message Milestone: Sent (\(message.timestamp))",
eventId: "sendMessageSentSent-\(message.timestamp)",
logInProduction: true
)
BenchManager.startEvent(
title: "Send Message Milestone: Marked as Sent (\(message.timestamp))",
eventId: "sendMessageMarkedAsSent-\(message.timestamp)",
logInProduction: true
)
BenchManager.benchAsync(title: "Send Message Milestone: Enqueue \(message.timestamp)") { benchmarkCompletion in
Self.enqueueSendAsyncWrite { writeTransaction in
outgoingMessagePreparer.insertMessage(linkPreviewDraft: linkPreviewDraft,
transaction: writeTransaction)
Self.messageSenderJobQueue.add(message: outgoingMessagePreparer,
transaction: writeTransaction)
writeTransaction.addSyncCompletion {
benchmarkCompletion()
}
if let persistenceCompletion = persistenceCompletion {
writeTransaction.addAsyncCompletionOnMain {
persistenceCompletion()
}
}
}
}
if message.hasRenderableContent() {
thread.donateSendMessageIntent(for: message, transaction: readTransaction)
}
return message
}
class func createUnsentMessage(body messageBody: MessageBody?,
mediaAttachments: [SignalAttachment],
thread: TSThread,
quotedReplyModel: OWSQuotedReplyModel? = nil,
linkPreviewDraft: OWSLinkPreviewDraft? = nil,
transaction: SDSAnyWriteTransaction) throws -> TSOutgoingMessage {
let preparer = OutgoingMessagePreparer(messageBody: messageBody,
mediaAttachments: mediaAttachments,
thread: thread,
quotedReplyModel: quotedReplyModel,
transaction: transaction)
preparer.insertMessage(linkPreviewDraft: linkPreviewDraft, transaction: transaction)
return try preparer.prepareMessage(transaction: transaction)
}
}
// MARK: -
extension OutgoingMessagePreparer {
@objc
public convenience init(messageBody: MessageBody?,
mediaAttachments: [SignalAttachment] = [],
thread: TSThread,
quotedReplyModel: OWSQuotedReplyModel? = nil,
transaction: SDSAnyReadTransaction) {
var attachments = mediaAttachments
let truncatedText: String?
let bodyRanges: MessageBodyRanges?
if let messageBody = messageBody, !messageBody.text.isEmpty {
if messageBody.text.lengthOfBytes(using: .utf8) >= kOversizeTextMessageSizeThreshold {
truncatedText = messageBody.text.truncated(toByteCount: kOversizeTextMessageSizeThreshold)
bodyRanges = messageBody.ranges
if let dataSource = DataSourceValue.dataSource(withOversizeText: messageBody.text) {
let attachment = SignalAttachment.attachment(dataSource: dataSource,
dataUTI: kOversizeTextAttachmentUTI)
attachments.append(attachment)
} else {
owsFailDebug("dataSource was unexpectedly nil")
}
} else {
truncatedText = messageBody.text
bodyRanges = messageBody.ranges
}
} else {
truncatedText = nil
bodyRanges = nil
}
let expiresInSeconds = thread.disappearingMessagesDuration(with: transaction)
assert(attachments.allSatisfy { !$0.hasError && !$0.mimeType.isEmpty })
let isVoiceMessage = attachments.count == 1 && attachments.last?.isVoiceMessage == true
var isViewOnceMessage = false
for attachment in mediaAttachments {
if attachment.isViewOnceAttachment {
assert(mediaAttachments.count == 1)
isViewOnceMessage = true
break
}
if attachment.isBorderless {
assert(mediaAttachments.count == 1)
break
}
}
// Discard quoted reply for view-once messages.
let quotedMessage: TSQuotedMessage? = (isViewOnceMessage
? nil
: quotedReplyModel?.buildQuotedMessageForSending())
let message = TSOutgoingMessageBuilder(
thread: thread,
messageBody: truncatedText,
bodyRanges: bodyRanges,
expiresInSeconds: expiresInSeconds,
isVoiceMessage: isVoiceMessage,
quotedMessage: quotedMessage,
isViewOnceMessage: isViewOnceMessage
).build(transaction: transaction)
let attachmentInfos = attachments.map { $0.buildOutgoingAttachmentInfo(message: message) }
self.init(message, unsavedAttachmentInfos: attachmentInfos)
}
}