156 lines
6.6 KiB
Swift
156 lines
6.6 KiB
Swift
//
|
|
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import PromiseKit
|
|
|
|
@objc
|
|
public protocol CameraFirstCaptureDelegate: AnyObject {
|
|
func cameraFirstCaptureSendFlowDidComplete(_ cameraFirstCaptureSendFlow: CameraFirstCaptureSendFlow)
|
|
func cameraFirstCaptureSendFlowDidCancel(_ cameraFirstCaptureSendFlow: CameraFirstCaptureSendFlow)
|
|
}
|
|
|
|
@objc
|
|
public class CameraFirstCaptureSendFlow: NSObject {
|
|
@objc
|
|
public weak var delegate: CameraFirstCaptureDelegate?
|
|
|
|
var approvedAttachments: [SignalAttachment]?
|
|
var approvalMessageText: String?
|
|
|
|
var selectedConversations: [ConversationItem] = []
|
|
|
|
// MARK: Dependencies
|
|
|
|
var databaseStorage: SDSDatabaseStorage {
|
|
return SSKEnvironment.shared.databaseStorage
|
|
}
|
|
|
|
var broadcastMediaMessageJobQueue: BroadcastMediaMessageJobQueue {
|
|
return AppEnvironment.shared.broadcastMediaMessageJobQueue
|
|
}
|
|
}
|
|
|
|
extension CameraFirstCaptureSendFlow: SendMediaNavDelegate {
|
|
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController) {
|
|
delegate?.cameraFirstCaptureSendFlowDidCancel(self)
|
|
}
|
|
|
|
func sendMediaNav(_ sendMediaNavigationController: SendMediaNavigationController, didApproveAttachments attachments: [SignalAttachment], messageText: String?) {
|
|
self.approvedAttachments = attachments
|
|
self.approvalMessageText = messageText
|
|
|
|
let pickerVC = ConversationPickerViewController()
|
|
pickerVC.delegate = self
|
|
sendMediaNavigationController.pushViewController(pickerVC, animated: true)
|
|
}
|
|
|
|
func sendMediaNavInitialMessageText(_ sendMediaNavigationController: SendMediaNavigationController) -> String? {
|
|
return approvalMessageText
|
|
}
|
|
|
|
func sendMediaNav(_ sendMediaNavigationController: SendMediaNavigationController, didChangeMessageText newMessageText: String?) {
|
|
self.approvalMessageText = newMessageText
|
|
}
|
|
|
|
var sendMediaNavApprovalButtonImageName: String {
|
|
return "arrow-right-24"
|
|
}
|
|
|
|
var sendMediaNavCanSaveAttachments: Bool {
|
|
return true
|
|
}
|
|
|
|
var sendMediaNavTextInputContextIdentifier: String? {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
extension CameraFirstCaptureSendFlow: ConversationPickerDelegate {
|
|
var selectedConversationsForConversationPicker: [ConversationItem] {
|
|
return selectedConversations
|
|
}
|
|
|
|
func conversationPicker(_ conversationPickerViewController: ConversationPickerViewController,
|
|
didSelectConversation conversation: ConversationItem) {
|
|
self.selectedConversations.append(conversation)
|
|
}
|
|
|
|
func conversationPicker(_ conversationPickerViewController: ConversationPickerViewController,
|
|
didDeselectConversation conversation: ConversationItem) {
|
|
self.selectedConversations = self.selectedConversations.filter {
|
|
$0.messageRecipient != conversation.messageRecipient
|
|
}
|
|
}
|
|
|
|
func conversationPickerDidCompleteSelection(_ conversationPickerViewController: ConversationPickerViewController) {
|
|
guard let approvedAttachments = self.approvedAttachments else {
|
|
owsFailDebug("approvedAttachments was unexpectedly nil")
|
|
delegate?.cameraFirstCaptureSendFlowDidCancel(self)
|
|
return
|
|
}
|
|
|
|
let conversations = selectedConversationsForConversationPicker
|
|
DispatchQueue.global().async(.promise) {
|
|
// Duplicate attachments per conversation
|
|
let conversationAttachments: [(ConversationItem, [SignalAttachment])] =
|
|
try conversations.map { conversation in
|
|
return (conversation, try approvedAttachments.map { try $0.cloneAttachment() })
|
|
}
|
|
|
|
// We only upload one set of attachments, and then copy the upload details into
|
|
// each conversation before sending.
|
|
let attachmentsToUpload: [OutgoingAttachmentInfo] = approvedAttachments.map { attachment in
|
|
return OutgoingAttachmentInfo(dataSource: attachment.dataSource,
|
|
contentType: attachment.mimeType,
|
|
sourceFilename: attachment.filenameOrDefault,
|
|
caption: attachment.captionText,
|
|
albumMessageId: nil)
|
|
}
|
|
|
|
self.databaseStorage.write { transaction in
|
|
var messages: [TSOutgoingMessage] = []
|
|
|
|
for (conversation, attachments) in conversationAttachments {
|
|
let thread: TSThread
|
|
switch conversation.messageRecipient {
|
|
case .contact(let address):
|
|
thread = TSContactThread.getOrCreateThread(withContactAddress: address,
|
|
transaction: transaction)
|
|
case .group(let groupThread):
|
|
thread = groupThread
|
|
}
|
|
|
|
let message = try! ThreadUtil.createUnsentMessage(withText: self.approvalMessageText,
|
|
mediaAttachments: attachments,
|
|
in: thread,
|
|
quotedReplyModel: nil,
|
|
linkPreviewDraft: nil,
|
|
transaction: transaction)
|
|
messages.append(message)
|
|
}
|
|
|
|
// map of attachments we'll upload to their copies in each recipient thread
|
|
var attachmentIdMap: [String: [String]] = [:]
|
|
let correspondingAttachmentIds = transpose(messages.map { $0.attachmentIds })
|
|
for (index, attachmentInfo) in attachmentsToUpload.enumerated() {
|
|
do {
|
|
let attachmentToUpload = try attachmentInfo.asStreamConsumingDataSource(withIsVoiceMessage: false)
|
|
attachmentToUpload.anyInsert(transaction: transaction)
|
|
|
|
attachmentIdMap[attachmentToUpload.uniqueId] = correspondingAttachmentIds[index]
|
|
} catch {
|
|
owsFailDebug("error: \(error)")
|
|
}
|
|
}
|
|
|
|
self.broadcastMediaMessageJobQueue.add(attachmentIdMap: attachmentIdMap,
|
|
transaction: transaction)
|
|
}
|
|
}.done { _ in
|
|
self.delegate?.cameraFirstCaptureSendFlowDidComplete(self)
|
|
}.retainUntilComplete()
|
|
}
|
|
}
|