Various improvements

This commit is contained in:
Ilya Laktyushin 2024-06-18 01:06:31 +04:00
parent 907e408dcc
commit a2348148ff
11 changed files with 250 additions and 39 deletions

View File

@ -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?";

View File

@ -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 {

View File

@ -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))

View File

@ -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
}

View File

@ -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)

View File

@ -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 {

View File

@ -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 }
)
}

View File

@ -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)
}
}

View File

@ -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):

View File

@ -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)
}
}

View File

@ -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)