mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
907e408dcc
commit
a2348148ff
@ -12223,11 +12223,15 @@ Sorry for the inconvenience.";
|
||||
"Chat.Context.Username.Copy" = "Copy Username";
|
||||
"Chat.Context.Username.NotOnTelegram" = "This user doesn't exist on Telegram.";
|
||||
|
||||
"Chat.Context.Hashtag.Search" = "View Profile";
|
||||
"Chat.Context.Hashtag.Search" = "Search";
|
||||
"Chat.Context.Hashtag.Copy" = "Copy Hashtag";
|
||||
|
||||
"Chat.Context.Card.Copy" = "Copy Card Number";
|
||||
|
||||
"Chat.Context.Command.Copy" = "Copy Command";
|
||||
|
||||
"Chat.Context.Timecode.Copy" = "Copy Timecode";
|
||||
|
||||
"Message.FactCheck" = "Fact Check";
|
||||
"Message.FactCheck.WhatIsThis" = "what's this?";
|
||||
|
||||
|
@ -1066,6 +1066,9 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo
|
||||
if case let .extracted(extracted) = self.source {
|
||||
if extracted.adjustContentHorizontally {
|
||||
contentFrame.origin.x = combinedActionsFrame.minX
|
||||
if contentFrame.maxX > layout.size.width {
|
||||
contentFrame.origin.x = layout.size.width - contentFrame.width - actionsEdgeInset
|
||||
}
|
||||
}
|
||||
if extracted.centerVertically {
|
||||
if combinedActionsFrame.height.isZero {
|
||||
|
@ -225,7 +225,7 @@ private final class ChatMessageActionButtonNode: ASDisplayNode {
|
||||
let titleColor = bubbleVariableColor(variableColor: messageTheme.actionButtonsTextColor, wallpaper: theme.wallpaper)
|
||||
let attributedTitle: NSAttributedString
|
||||
if isStarsPayment {
|
||||
let updatedTitle = title.replacingOccurrences(of: "⭐️", with: " # ")
|
||||
let updatedTitle = title.replacingOccurrences(of: "⭐️", with: " # ")
|
||||
let buttonAttributedString = NSMutableAttributedString(string: updatedTitle, font: titleFont, textColor: titleColor, paragraphAlignment: .center)
|
||||
if let range = buttonAttributedString.string.range(of: "#"), let starImage = UIImage(bundleImageName: "Item List/PremiumIcon") {
|
||||
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
||||
|
@ -163,11 +163,13 @@ public struct ChatMessageBubbleContentTapAction {
|
||||
}
|
||||
|
||||
public var content: Content
|
||||
public var rects: [CGRect]?
|
||||
public var hasLongTapAction: Bool
|
||||
public var activate: (() -> Promise<Bool>?)?
|
||||
|
||||
public init(content: Content, hasLongTapAction: Bool = true, activate: (() -> Promise<Bool>?)? = nil) {
|
||||
public init(content: Content, rects: [CGRect]? = nil, hasLongTapAction: Bool = true, activate: (() -> Promise<Bool>?)? = nil) {
|
||||
self.content = content
|
||||
self.rects = rects
|
||||
self.hasLongTapAction = hasLongTapAction
|
||||
self.activate = activate
|
||||
}
|
||||
|
@ -4649,6 +4649,13 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
let convertedLocation = self.view.convert(location, to: contentNode.view)
|
||||
|
||||
let tapAction = contentNode.tapActionAtPoint(convertedLocation, gesture: gesture, isEstimating: false)
|
||||
var rects: [CGRect] = []
|
||||
if let actionRects = tapAction.rects {
|
||||
for rect in actionRects {
|
||||
rects.append(rect.offsetBy(dx: contentNode.frame.minX, dy: contentNode.frame.minY))
|
||||
}
|
||||
}
|
||||
|
||||
switch tapAction.content {
|
||||
case .none:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(CGPoint(x: self.frame.width - location.x, y: location.y)), let tapMessage = self.item?.controllerInteraction.tapMessage {
|
||||
@ -4692,13 +4699,11 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
case let .phone(number):
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
guard let self, let item = self.item, let contentNode = self.contextContentNodeForLink(number) else {
|
||||
guard let self, let item = self.item, let contentNode = self.contextContentNodeForLink(number, rects: rects) else {
|
||||
return
|
||||
}
|
||||
|
||||
item.controllerInteraction.longTap(.phone(number), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
|
||||
// item.controllerInteraction.openPhoneContextMenu(ChatControllerInteraction.OpenPhone(number: number, message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
|
||||
case let .peerMention(peerId, _, openProfile):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
@ -4768,7 +4773,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
case let .bankCard(number):
|
||||
if let item = self.item {
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.bankCard(number), ChatControllerInteraction.LongTapParams(message: item.message, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
@ -4854,6 +4859,13 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
tapMessage = contentNode.item?.message
|
||||
}
|
||||
let tapAction = contentNode.tapActionAtPoint(convertedLocation, gesture: gesture, isEstimating: false)
|
||||
var rects: [CGRect] = []
|
||||
if let actionRects = tapAction.rects {
|
||||
for rect in actionRects {
|
||||
rects.append(rect.offsetBy(dx: contentNode.frame.minX, dy: contentNode.frame.minY))
|
||||
}
|
||||
}
|
||||
|
||||
switch tapAction.content {
|
||||
case .none, .ignore:
|
||||
break
|
||||
@ -4861,7 +4873,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
if tapAction.hasLongTapAction {
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
let cleanUrl = url.url.replacingOccurrences(of: "mailto:", with: "")
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(cleanUrl) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(cleanUrl, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.url(url.url), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
@ -4871,35 +4883,35 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
case let .phone(number):
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.phone(number), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
}, contextMenuOnLongPress: !tapAction.hasLongTapAction))
|
||||
case let .peerMention(peerId, mention, _):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(mention) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(mention, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.peerMention(peerId, mention), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
})
|
||||
case let .textMention(name):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(name) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(name, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.mention(name), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
})
|
||||
case let .botCommand(command):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(command) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(command, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.command(command), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
})
|
||||
case let .hashtag(_, hashtag):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(hashtag) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(hashtag, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.hashtag(hashtag), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
@ -4917,7 +4929,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
case let .timecode(timecode, text):
|
||||
if let mediaMessage = mediaMessage {
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(text) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(text, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.timecode(timecode, text), ChatControllerInteraction.LongTapParams(message: mediaMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
@ -4925,7 +4937,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
case let .bankCard(number):
|
||||
return .action(InternalBubbleTapAction.Action { [weak self] in
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number) else {
|
||||
guard let self, let contentNode = self.contextContentNodeForLink(number, rects: rects) else {
|
||||
return
|
||||
}
|
||||
item.controllerInteraction.longTap(.bankCard(number), ChatControllerInteraction.LongTapParams(message: item.content.firstMessage, contentNode: contentNode, messageNode: self, progress: tapAction.activate?()))
|
||||
@ -4963,7 +4975,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
return nil
|
||||
}
|
||||
|
||||
private func contextContentNodeForLink(_ link: String) -> ContextExtractedContentContainingNode? {
|
||||
private func contextContentNodeForLink(_ link: String, rects: [CGRect]?) -> ContextExtractedContentContainingNode? {
|
||||
guard let item = self.item else {
|
||||
return nil
|
||||
}
|
||||
@ -4972,8 +4984,9 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
let incoming = item.content.effectivelyIncoming(item.context.account.peerId, associatedData: item.associatedData)
|
||||
|
||||
let textNode = ImmediateTextNode()
|
||||
textNode.maximumNumberOfLines = 2
|
||||
textNode.attributedText = NSAttributedString(string: link, font: Font.regular(item.presentationData.fontSize.baseDisplaySize), textColor: incoming ? item.presentationData.theme.theme.chat.message.incoming.linkTextColor : item.presentationData.theme.theme.chat.message.outgoing.linkTextColor)
|
||||
let textSize = textNode.updateLayout(CGSize(width: 1000.0, height: 100.0))
|
||||
let textSize = textNode.updateLayout(CGSize(width: self.bounds.width - 32.0, height: 100.0))
|
||||
|
||||
let backgroundNode = ASDisplayNode()
|
||||
backgroundNode.backgroundColor = (incoming ? item.presentationData.theme.theme.chat.message.incoming.bubble.withoutWallpaper.fill : item.presentationData.theme.theme.chat.message.outgoing.bubble.withoutWallpaper.fill).first ?? .black
|
||||
@ -4986,7 +4999,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
textNode.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: textSize)
|
||||
backgroundNode.addSubnode(textNode)
|
||||
|
||||
containingNode.frame = CGRect(origin: CGPoint(x: self.backgroundNode.frame.minX + 3.0, y: 1.0), size: CGSize(width: backgroundSize.width, height: backgroundSize.height + 20.0))
|
||||
var origin = CGPoint(x: self.backgroundNode.frame.minX + 3.0, y: 1.0)
|
||||
if let rect = rects?.first {
|
||||
origin = rect.origin
|
||||
}
|
||||
|
||||
containingNode.frame = CGRect(origin: origin, size: CGSize(width: backgroundSize.width, height: backgroundSize.height + 20.0))
|
||||
containingNode.contentNode.frame = CGRect(origin: .zero, size: backgroundSize)
|
||||
containingNode.contentRect = CGRect(origin: .zero, size: backgroundSize)
|
||||
containingNode.contentNode.addSubnode(backgroundNode)
|
||||
|
@ -929,6 +929,24 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let textNodeFrame = self.textNode.textNode.frame
|
||||
let textLocalPoint = CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)
|
||||
if let (index, attributes) = self.textNode.textNode.attributesAtPoint(textLocalPoint) {
|
||||
var rects: [CGRect]?
|
||||
let possibleNames: [String] = [
|
||||
TelegramTextAttributes.URL,
|
||||
TelegramTextAttributes.PeerMention,
|
||||
TelegramTextAttributes.PeerTextMention,
|
||||
TelegramTextAttributes.BotCommand,
|
||||
TelegramTextAttributes.Hashtag,
|
||||
TelegramTextAttributes.Timecode,
|
||||
TelegramTextAttributes.BankCard
|
||||
]
|
||||
for name in possibleNames {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: name)] {
|
||||
rects = self.textNode.textNode.attributeRects(name: name, at: index)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)], !self.displayContentsUnderSpoilers.value {
|
||||
return ChatMessageBubbleContentTapAction(content: .none)
|
||||
} else if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
@ -946,28 +964,28 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
content = .url(ChatMessageBubbleContentTapAction.Url(url: url, concealed: concealed))
|
||||
}
|
||||
|
||||
return ChatMessageBubbleContentTapAction(content: content, activate: makeActivate(urlRange))
|
||||
return ChatMessageBubbleContentTapAction(content: content, rects: rects, activate: makeActivate(urlRange))
|
||||
} else if let peerMention = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)] as? TelegramPeerMention {
|
||||
return ChatMessageBubbleContentTapAction(content: .peerMention(peerId: peerMention.peerId, mention: peerMention.mention, openProfile: false))
|
||||
return ChatMessageBubbleContentTapAction(content: .peerMention(peerId: peerMention.peerId, mention: peerMention.mention, openProfile: false), rects: rects)
|
||||
} else if let peerName = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
|
||||
var urlRange: NSRange?
|
||||
if let (_, _, urlRangeValue) = self.textNode.textNode.attributeSubstringWithRange(name: TelegramTextAttributes.PeerTextMention, index: index) {
|
||||
urlRange = urlRangeValue
|
||||
}
|
||||
|
||||
return ChatMessageBubbleContentTapAction(content: .textMention(peerName), activate: makeActivate(urlRange))
|
||||
return ChatMessageBubbleContentTapAction(content: .textMention(peerName), rects: rects, activate: makeActivate(urlRange))
|
||||
} else if let botCommand = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BotCommand)] as? String {
|
||||
return ChatMessageBubbleContentTapAction(content: .botCommand(botCommand))
|
||||
return ChatMessageBubbleContentTapAction(content: .botCommand(botCommand), rects: rects)
|
||||
} else if let hashtag = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
|
||||
return ChatMessageBubbleContentTapAction(content: .hashtag(hashtag.peerName, hashtag.hashtag))
|
||||
return ChatMessageBubbleContentTapAction(content: .hashtag(hashtag.peerName, hashtag.hashtag), rects: rects)
|
||||
} else if let timecode = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Timecode)] as? TelegramTimecode {
|
||||
return ChatMessageBubbleContentTapAction(content: .timecode(timecode.time, timecode.text))
|
||||
return ChatMessageBubbleContentTapAction(content: .timecode(timecode.time, timecode.text), rects: rects)
|
||||
} else if let bankCard = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.BankCard)] as? String {
|
||||
var urlRange: NSRange?
|
||||
if let (_, _, urlRangeValue) = self.textNode.textNode.attributeSubstringWithRange(name: TelegramTextAttributes.BankCard, index: index) {
|
||||
urlRange = urlRangeValue
|
||||
}
|
||||
return ChatMessageBubbleContentTapAction(content: .bankCard(bankCard), activate: makeActivate(urlRange))
|
||||
return ChatMessageBubbleContentTapAction(content: .bankCard(bankCard), rects: rects, activate: makeActivate(urlRange))
|
||||
} else if let pre = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre)] as? String {
|
||||
return ChatMessageBubbleContentTapAction(content: .copy(pre))
|
||||
} else if let code = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Code)] as? String {
|
||||
|
@ -69,6 +69,7 @@ public enum CodableDrawingEntity: Equatable {
|
||||
var size: CGSize?
|
||||
var rotation: CGFloat?
|
||||
var scale: CGFloat?
|
||||
var cornerRadius: Double?
|
||||
|
||||
switch self {
|
||||
case let .location(entity):
|
||||
@ -76,6 +77,9 @@ public enum CodableDrawingEntity: Equatable {
|
||||
size = entity.renderImage?.size
|
||||
rotation = entity.rotation
|
||||
scale = entity.scale
|
||||
if let size {
|
||||
cornerRadius = 10.0 / (size.width * entity.scale)
|
||||
}
|
||||
case let .sticker(entity):
|
||||
var entityPosition = entity.position
|
||||
var entitySize = entity.baseSize
|
||||
@ -83,7 +87,7 @@ public enum CodableDrawingEntity: Equatable {
|
||||
let entityScale = entity.scale
|
||||
|
||||
if case .message = entity.content {
|
||||
let offset: CGFloat = 16.18 * entityScale //54.0 * entityScale / 3.337
|
||||
let offset: CGFloat = 16.18 * entityScale
|
||||
entitySize = CGSize(width: entitySize.width - 38.0, height: entitySize.height - 4.0)
|
||||
entityPosition = CGPoint(x: entityPosition.x + offset * cos(entityRotation), y: entityPosition.y + offset * sin(entityRotation))
|
||||
}
|
||||
@ -94,9 +98,17 @@ public enum CodableDrawingEntity: Equatable {
|
||||
scale = entityScale
|
||||
case let .link(entity):
|
||||
position = entity.position
|
||||
size = entity.renderImage?.size
|
||||
rotation = entity.rotation
|
||||
scale = entity.scale
|
||||
if let entitySize = entity.renderImage?.size {
|
||||
if entity.whiteImage != nil {
|
||||
cornerRadius = 38.0 / (entitySize.width * entity.scale)
|
||||
size = CGSize(width: entitySize.width - 28.0, height: entitySize.height - 26.0)
|
||||
} else {
|
||||
cornerRadius = 10.0 / (entitySize.width * entity.scale)
|
||||
size = entitySize
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@ -105,13 +117,16 @@ public enum CodableDrawingEntity: Equatable {
|
||||
return nil
|
||||
}
|
||||
|
||||
let width = size.width * scale / 1080.0 * 100.0
|
||||
let height = size.height * scale / 1920.0 * 100.0
|
||||
|
||||
return MediaArea.Coordinates(
|
||||
x: position.x / 1080.0 * 100.0,
|
||||
y: position.y / 1920.0 * 100.0,
|
||||
width: size.width * scale / 1080.0 * 100.0,
|
||||
height: size.height * scale / 1920.0 * 100.0,
|
||||
width: width,
|
||||
height: height,
|
||||
rotation: rotation / .pi * 180.0,
|
||||
cornerRadius: nil
|
||||
cornerRadius: cornerRadius.flatMap { $0 * 100.0 }
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import ContextUI
|
||||
import UndoUI
|
||||
import AccountContext
|
||||
import ChatMessageItemView
|
||||
import ChatMessageItemCommon
|
||||
import ChatControllerInteraction
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func openCommandContextMenu(command: String, params: ChatControllerInteraction.LongTapParams) -> Void {
|
||||
guard let message = params.message, let contentNode = params.contentNode else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) else {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil// anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||
let gesture: ContextGesture? = nil // anyRecognizer as? ContextGesture
|
||||
|
||||
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(ChatMessageLinkContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
|
||||
// }
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Command_Copy, 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 = command
|
||||
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}))
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -26,16 +26,11 @@ extension ChatControllerImpl {
|
||||
case let .peerMention(peerId, mention):
|
||||
self.openMentionContextMenu(username: mention, peerId: peerId, params: params)
|
||||
case let .command(command):
|
||||
let _ = command
|
||||
break
|
||||
// self.openBotCommandContextMenu(command: command, params: params)
|
||||
self.openCommandContextMenu(command: command, params: params)
|
||||
case let .hashtag(hashtag):
|
||||
self.openHashtagContextMenu(hashtag: hashtag, params: params)
|
||||
case let .timecode(value, timecode):
|
||||
let _ = value
|
||||
let _ = timecode
|
||||
break
|
||||
// self.openTimecodeContextMenu(timecode: timecode, params: params)
|
||||
self.openTimecodeContextMenu(timecode: timecode, value: value, params: params)
|
||||
case let .bankCard(number):
|
||||
self.openBankCardContextMenu(number: number, params: params)
|
||||
case let .phone(number):
|
||||
|
@ -0,0 +1,69 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import ContextUI
|
||||
import UndoUI
|
||||
import AccountContext
|
||||
import ChatMessageItemView
|
||||
import ChatMessageItemCommon
|
||||
import ChatControllerInteraction
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func openTimecodeContextMenu(timecode: String, value: Double, params: ChatControllerInteraction.LongTapParams) -> Void {
|
||||
guard let message = params.message, let contentNode = params.contentNode else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let messages = self.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) else {
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil// anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||
let gesture: ContextGesture? = nil // anyRecognizer as? ContextGesture
|
||||
|
||||
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(ChatMessageLinkContextExtractedContentSource(chatNode: self.chatDisplayNode, contentNode: contentNode))
|
||||
// }
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Chat_Context_Timecode_Copy, 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 = timecode
|
||||
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}))
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
@ -322,10 +322,15 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
messageUpdated = true
|
||||
}
|
||||
|
||||
var isStarsPayment = false
|
||||
if let message = interfaceState.pinnedMessage, !message.message.isRestricted(platform: "ios", contentSettings: self.context.currentContentSettings.with { $0 }) {
|
||||
for attribute in message.message.attributes {
|
||||
if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), attribute.rows.count == 1, attribute.rows[0].buttons.count == 1 {
|
||||
actionTitle = attribute.rows[0].buttons[0].title
|
||||
let title = attribute.rows[0].buttons[0].title
|
||||
actionTitle = title
|
||||
if case .payment = attribute.rows[0].buttons[0].action, title.contains("⭐️") {
|
||||
isStarsPayment = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -430,7 +435,20 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
||||
self.actionButtonBackgroundNode.isHidden = false
|
||||
self.actionButtonTitleNode.isHidden = false
|
||||
|
||||
self.actionButtonTitleNode.attributedText = NSAttributedString(string: actionTitle, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: interfaceState.theme.list.itemCheckColors.foregroundColor)
|
||||
let attributedTitle: NSAttributedString
|
||||
if isStarsPayment {
|
||||
let updatedTitle = actionTitle.replacingOccurrences(of: "⭐️", with: " # ")
|
||||
let buttonAttributedString = NSMutableAttributedString(string: updatedTitle, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: interfaceState.theme.list.itemCheckColors.foregroundColor)
|
||||
if let range = buttonAttributedString.string.range(of: "#"), let starImage = UIImage(bundleImageName: "Item List/PremiumIcon") {
|
||||
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
||||
buttonAttributedString.addAttribute(.foregroundColor, value: interfaceState.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string))
|
||||
buttonAttributedString.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: buttonAttributedString.string))
|
||||
}
|
||||
attributedTitle = buttonAttributedString
|
||||
} else {
|
||||
attributedTitle = NSAttributedString(string: actionTitle, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: interfaceState.theme.list.itemCheckColors.foregroundColor)
|
||||
}
|
||||
self.actionButtonTitleNode.attributedText = attributedTitle
|
||||
|
||||
let actionButtonTitleSize = self.actionButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude))
|
||||
let actionButtonSize = CGSize(width: max(actionButtonTitleSize.width + 20.0, 40.0), height: 28.0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user