mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
242 lines
13 KiB
Swift
242 lines
13 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
import TelegramCore
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import TelegramNotices
|
|
import ContextUI
|
|
import AccountContext
|
|
import ChatMessageItemView
|
|
import ChatMessageItemCommon
|
|
import AvatarNode
|
|
import UndoUI
|
|
import MessageUI
|
|
import PeerInfoUI
|
|
|
|
extension ChatControllerImpl: MFMessageComposeViewControllerDelegate {
|
|
func openPhoneContextMenu(number: String, peer: EnginePeer?, message: Message, contentNode: ContextExtractedContentContainingNode, messageNode: ASDisplayNode, frame: CGRect, anyRecognizer: UIGestureRecognizer?, location: CGPoint?) -> Void {
|
|
if self.presentationInterfaceState.interfaceState.selectionState != nil {
|
|
return
|
|
}
|
|
|
|
self.dismissAllTooltips()
|
|
|
|
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
|
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
|
|
|
|
if let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) {
|
|
(self.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
|
|
self.chatDisplayNode.cancelInteractiveKeyboardGestures()
|
|
var updatedMessages = messages
|
|
for i in 0 ..< updatedMessages.count {
|
|
if updatedMessages[i].id == message.id {
|
|
let message = updatedMessages.remove(at: i)
|
|
updatedMessages.insert(message, at: 0)
|
|
break
|
|
}
|
|
}
|
|
|
|
self.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
|
|
|
let source: ContextContentSource
|
|
if let location = location {
|
|
source = .location(ChatMessageContextLocationContentSource(controller: self, location: messageNode.view.convert(messageNode.bounds, to: nil).origin.offsetBy(dx: location.x, dy: location.y)))
|
|
} else {
|
|
source = .extracted(ChatMessagePhoneContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
|
|
// source = .extracted(ChatMessageContextExtractedContentSource(chatController: self, chatNode: self.chatDisplayNode, engine: self.context.engine, message: message, selectAll: false))
|
|
}
|
|
|
|
var items: [ContextMenuItem] = []
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_AddToContacts, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
|
guard let self, let c else {
|
|
return
|
|
}
|
|
let basicData = DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [
|
|
DeviceContactPhoneNumberData(label: "", value: number)
|
|
])
|
|
let contactData = DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
|
|
|
|
pushContactContextOptionsController(context: self.context, contextController: c, presentationData: self.presentationData, peer: nil, contactData: contactData, parentController: self, push: { [weak self] c in
|
|
self?.push(c)
|
|
})
|
|
}))
|
|
)
|
|
items.append(.separator)
|
|
if let peer {
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_SendMessage, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.openPeer(peer: peer, navigation: .chat(textInputState: nil, subject: nil, peekData: nil), fromMessage: nil)
|
|
}))
|
|
)
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVoiceCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.controllerInteraction?.callPeer(peer.id, false)
|
|
}))
|
|
)
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_TelegramVideoCall, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/VideoCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.controllerInteraction?.callPeer(peer.id, true)
|
|
}))
|
|
)
|
|
} else {
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_InviteToTelegram, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Telegram"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.inviteToTelegram(numbers: [number])
|
|
}))
|
|
)
|
|
}
|
|
if number.hasPrefix("+888") {
|
|
|
|
} else {
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CallViaCarrier, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PhoneCall"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.openUrl("tel:\(number)", concealed: false)
|
|
}))
|
|
)
|
|
}
|
|
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_CopyNumber, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
|
|
UIPasteboard.general.string = number
|
|
|
|
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_PhoneCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
|
}))
|
|
)
|
|
|
|
items.append(.separator)
|
|
if let peer {
|
|
let avatarSize = CGSize(width: 28.0, height: 28.0)
|
|
let avatarSignal = peerAvatarCompleteImage(account: self.context.account, peer: peer, size: avatarSize)
|
|
|
|
let subtitle = NSMutableAttributedString(string: self.presentationData.strings.Chat_Context_Phone_ViewProfile + " >")
|
|
if let range = subtitle.string.range(of: ">"), let arrowImage = UIImage(bundleImageName: "Item List/InlineTextRightArrow") {
|
|
subtitle.addAttribute(.attachment, value: arrowImage, range: NSRange(range, in: subtitle.string))
|
|
subtitle.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: subtitle.string))
|
|
}
|
|
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), textLayout: .secondLineWithAttributedValue(subtitle), icon: { theme in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), iconPosition: .left, action: { [weak self] _, f in
|
|
f(.default)
|
|
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.openPeer(peer: peer, navigation: .info(nil), fromMessage: nil)
|
|
}))
|
|
)
|
|
} else {
|
|
let emptyAction: ((ContextMenuActionItem.Action) -> Void)? = nil
|
|
items.append(
|
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Phone_NotOnTelegram, textLayout: .multiline, textFont: .small, icon: { _ in return nil }, action: emptyAction))
|
|
)
|
|
}
|
|
|
|
self.canReadHistory.set(false)
|
|
|
|
let controller = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), recognizer: recognizer, gesture: gesture, disableScreenshots: false)
|
|
controller.dismissed = { [weak self] in
|
|
self?.canReadHistory.set(true)
|
|
}
|
|
|
|
self.window?.presentInGlobalOverlay(controller)
|
|
}
|
|
}
|
|
|
|
private func inviteToTelegram(numbers: [String]) {
|
|
if MFMessageComposeViewController.canSendText() {
|
|
let composer = MFMessageComposeViewController()
|
|
composer.messageComposeDelegate = self
|
|
composer.recipients = Array(Set(numbers))
|
|
let url = self.presentationData.strings.InviteText_URL
|
|
let body = self.presentationData.strings.InviteText_SingleContact(url).string
|
|
composer.body = body
|
|
self.messageComposeController = composer
|
|
if let window = self.view.window {
|
|
window.rootViewController?.present(composer, animated: true)
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc public func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
|
|
self.messageComposeController = nil
|
|
|
|
controller.dismiss(animated: true, completion: nil)
|
|
}
|
|
}
|
|
|
|
private final class ChatMessagePhoneContextExtractedContentSource: ContextExtractedContentSource {
|
|
let keepInPlace: Bool = false
|
|
let ignoreContentTouches: Bool = true
|
|
let blurBackground: Bool = true
|
|
let adjustContentHorizontally = true
|
|
|
|
private weak var chatNode: ChatControllerNode?
|
|
private let contentNode: ContextExtractedContentContainingNode
|
|
|
|
var shouldBeDismissed: Signal<Bool, NoError> {
|
|
return .single(false)
|
|
}
|
|
|
|
init(chatNode: ChatControllerNode, contentNode: ContextExtractedContentContainingNode) {
|
|
self.chatNode = chatNode
|
|
self.contentNode = contentNode
|
|
}
|
|
|
|
func takeView() -> ContextControllerTakeViewInfo? {
|
|
guard let chatNode = self.chatNode else {
|
|
return nil
|
|
}
|
|
|
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
|
transition.updateAlpha(node: self.contentNode.contentNode, alpha: 1.0)
|
|
|
|
return ContextControllerTakeViewInfo(containingItem: .node(self.contentNode), contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
|
|
}
|
|
|
|
func putBack() -> ContextControllerPutBackViewInfo? {
|
|
guard let chatNode = self.chatNode else {
|
|
return nil
|
|
}
|
|
|
|
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
|
|
transition.updateAlpha(node: self.contentNode.contentNode, alpha: 0.0, completion: { _ in
|
|
self.contentNode.removeFromSupernode()
|
|
})
|
|
|
|
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: chatNode.convert(chatNode.frameForVisibleArea(), to: nil))
|
|
}
|
|
}
|