Swiftgram/submodules/TelegramUI/Sources/ChatControllerOpenMessageShareMenu.swift
2024-01-16 21:14:24 +04:00

216 lines
12 KiB
Swift

import Foundation
import TelegramPresentationData
import AccountContext
import Postbox
import TelegramCore
import SwiftSignalKit
import ContextUI
import ChatControllerInteraction
import Display
import UIKit
import UndoUI
import ShareController
import ChatQrCodeScreen
import ChatShareMessageTagView
import ReactionSelectionNode
extension ChatControllerImpl {
func openMessageShareMenu(id: EngineMessage.Id) {
guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(id), let message = messages.first else {
return
}
let chatPresentationInterfaceState = self.presentationInterfaceState
var warnAboutPrivate = false
var canShareToStory = false
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = message.peers[message.id.peerId] as? TelegramChannel {
if case .broadcast = channel.info {
canShareToStory = true
}
if channel.addressName == nil {
warnAboutPrivate = true
}
}
let shareController = ShareController(context: self.context, subject: .messages(messages), updatedPresentationData: self.updatedPresentationData, shareAsLink: true)
shareController.parentNavigationController = self.navigationController as? NavigationController
if let message = messages.first, message.media.contains(where: { media in
if media is TelegramMediaContact || media is TelegramMediaPoll {
return true
} else if let file = media as? TelegramMediaFile, file.isSticker || file.isAnimatedSticker || file.isVideoSticker {
return true
} else {
return false
}
}) {
canShareToStory = false
}
if message.text.containsOnlyEmoji {
canShareToStory = false
}
if canShareToStory {
shareController.shareStory = { [weak self] in
guard let self else {
return
}
Queue.mainQueue().after(0.15) {
self.openStorySharing(messages: messages)
}
}
}
shareController.openShareAsImage = { [weak self] messages in
guard let self else {
return
}
self.present(ChatQrCodeScreen(context: self.context, subject: .messages(messages)), in: .window(.root))
}
shareController.dismissed = { [weak self] shared in
if shared {
self?.commitPurposefulAction()
}
}
shareController.actionCompleted = { [weak self] in
guard let self else {
return
}
let content: UndoOverlayContent
if warnAboutPrivate {
content = .linkCopied(text: self.presentationData.strings.Conversation_PrivateMessageLinkCopiedLong)
} else {
content = .linkCopied(text: self.presentationData.strings.Conversation_LinkCopied)
}
self.present(UndoOverlayController(presentationData: self.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
shareController.enqueued = { [weak self] peerIds, correlationIds in
guard let self else {
return
}
let _ = (self.context.engine.data.get(
EngineDataList(
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
)
)
|> deliverOnMainQueue).startStandalone(next: { [weak self] peerList in
guard let self else {
return
}
let peers = peerList.compactMap { $0 }
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let text: String
var savedMessages = false
if peerIds.count == 1, let peerId = peerIds.first, peerId == self.context.account.peerId {
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
savedMessages = true
} else {
if peers.count == 1, let peer = peers.first {
var peerName = peer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
peerName = peerName.replacingOccurrences(of: "**", with: "")
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
var firstPeerName = firstPeer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "")
var secondPeerName = secondPeer.id == self.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "")
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
} else if let peer = peers.first {
var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
peerName = peerName.replacingOccurrences(of: "**", with: "")
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(peers.count - 1)").string
} else {
text = ""
}
}
let reactionItems: Signal<[ReactionItem], NoError>
if savedMessages {
reactionItems = tagMessageReactions(context: self.context)
} else {
reactionItems = .single([])
}
let _ = (reactionItems
|> deliverOnMainQueue).startStandalone(next: { [weak self] reactionItems in
guard let self else {
return
}
self.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages ? .top : .bottom, animateInAsReplacement: !savedMessages, action: { [weak self] action in
if savedMessages, let self, action == .info {
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let self, let peer else {
return
}
guard let navigationController = self.navigationController as? NavigationController else {
return
}
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer)))
})
}
return false
}, additionalView: savedMessages ? { [weak self] () -> UndoOverlayControllerAdditionalView? in
guard let self else {
return nil
}
return ChatShareMessageTagView(context: self.context, presentationData: self.presentationData, reactionItems: reactionItems, completion: { [weak self] file, updateReaction in
guard let self else {
return
}
let _ = (self.context.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId: context.account.peerId, threadId: nil), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 45, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: [])
|> map { view, _, _ -> [EngineMessage.Id] in
//TODO:filter?
for entry in view.entries.reversed() {
if entry.message.id.namespace == Namespaces.Message.Cloud {
return [entry.message.id]
}
}
return view.entries.compactMap { entry -> EngineMessage.Id? in
for attribute in entry.message.attributes {
if let attribute = attribute as? OutgoingMessageInfoAttribute {
if let correlationId = attribute.correlationId {
if correlationIds.contains(correlationId) {
if entry.message.id.namespace == Namespaces.Message.Cloud {
return entry.message.id
} else {
return nil
}
}
}
}
}
return nil
}
}
|> filter { !$0.isEmpty }
|> take(1)
|> timeout(5.0, queue: .mainQueue(), alternate: .single([]))
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
guard let self else {
return
}
if let messageId = messageIds.first {
let _ = context.engine.messages.setMessageReactions(id: messageId, reactions: [updateReaction])
var isBuiltinReaction = false
if case .builtin = updateReaction {
isBuiltinReaction = true
}
self.present(UndoOverlayController(presentationData: presentationData, content: .messageTagged(context: self.context, customEmoji: file, isBuiltinReaction: isBuiltinReaction), elevatedLayout: false, position: .top, animateInAsReplacement: true, action: { _ in
return false
}), in: .current)
}
})
})
} : nil), in: .current)
})
})
}
self.chatDisplayNode.dismissInput()
self.present(shareController, in: .window(.root), blockInteraction: true)
}
}