diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TranslationMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TranslationMessageAttribute.swift index 4b64fd60ad..a54d1861e6 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TranslationMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TranslationMessageAttribute.swift @@ -1,11 +1,10 @@ import Postbox public class TranslationMessageAttribute: MessageAttribute, Equatable { - public struct Additional : PostboxCoding, Equatable { - public let text: String public let entities: [MessageTextEntity] + public init(text: String, entities: [MessageTextEntity]) { self.text = text self.entities = entities @@ -19,16 +18,14 @@ public class TranslationMessageAttribute: MessageAttribute, Equatable { public func encode(_ encoder: PostboxEncoder) { encoder.encodeString(self.text, forKey: "text") encoder.encodeObjectArray(self.entities, forKey: "entities") - } - - + } } public let text: String public let entities: [MessageTextEntity] public let toLang: String - public let additional:[Additional] + public let additional: [Additional] public var associatedPeerIds: [PeerId] { return [] diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/BUILD index 7a038fc101..4ed8c14938 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/BUILD @@ -27,6 +27,7 @@ swift_library( "//submodules/TelegramUI/Components/Chat/PollBubbleTimerNode", "//submodules/TelegramUI/Components/Chat/MergedAvatarsNode", "//submodules/TelegramUI/Components/TextNodeWithEntities", + "//submodules/TelegramUI/Components/Chat/ShimmeringLinkNode", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift index 8003318a44..4d49dca6b9 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift @@ -17,6 +17,7 @@ import ChatMessageItemCommon import PollBubbleTimerNode import MergedAvatarsNode import TextNodeWithEntities +import ShimmeringLinkNode private final class ChatMessagePollOptionRadioNodeParameters: NSObject { let timestamp: Double @@ -387,7 +388,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { private(set) var radioNode: ChatMessagePollOptionRadioNode? private let percentageNode: ASDisplayNode private var percentageImage: UIImage? - private var titleNode: TextNodeWithEntities? + fileprivate var titleNode: TextNodeWithEntities? private let buttonNode: HighlightTrackingButtonNode let separatorNode: ASDisplayNode private let resultBarNode: ASImageNode @@ -491,22 +492,29 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { } } - static func asyncLayout(_ maybeNode: ChatMessagePollOptionNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode))) { + static func asyncLayout(_ maybeNode: ChatMessagePollOptionNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ translation: TranslationMessageAttribute.Additional?, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode))) { let makeTitleLayout = TextNodeWithEntities.asyncLayout(maybeNode?.titleNode) let currentResult = maybeNode?.currentResult let currentSelection = maybeNode?.currentSelection let currentTheme = maybeNode?.theme - return { context, presentationData, message, poll, option, optionResult, constrainedWidth in + return { context, presentationData, message, poll, option, translation, optionResult, constrainedWidth in let leftInset: CGFloat = 50.0 let rightInset: CGFloat = 12.0 let incoming = message.effectivelyIncoming(context.account.peerId) + var optionText = option.text + var optionEntities = option.entities + if let translation { + optionText = translation.text + optionEntities = translation.entities + } + let optionTextColor: UIColor = incoming ? presentationData.theme.theme.chat.message.incoming.primaryTextColor : presentationData.theme.theme.chat.message.outgoing.primaryTextColor let optionAttributedText = stringWithAppliedEntities( - option.text, - entities: option.entities, + optionText, + entities: optionEntities, baseColor: optionTextColor, linkColor: optionTextColor, baseFont: presentationData.messageFont, @@ -627,6 +635,25 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { node.buttonNode.accessibilityLabel = option.text + if animated { + if let titleNode = node.titleNode, let cachedLayout = titleNode.textNode.cachedLayout { + if !cachedLayout.areLinesEqual(to: titleLayout) { + if let textContents = titleNode.textNode.contents { + let fadeNode = ASDisplayNode() + fadeNode.displaysAsynchronously = false + fadeNode.contents = textContents + fadeNode.frame = titleNode.textNode.frame + fadeNode.isLayerBacked = true + node.addSubnode(fadeNode) + fadeNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak fadeNode] _ in + fadeNode?.removeFromSupernode() + }) + titleNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) + } + } + } + } + let titleNode = titleApply(TextNodeWithEntities.Arguments( context: context, cache: context.animationCache, @@ -828,6 +855,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { private let buttonNode: HighlightableButtonNode private let statusNode: ChatMessageDateAndStatusNode private var optionNodes: [ChatMessagePollOptionNode] = [] + private var shimmeringNodes: [ShimmeringLinkNode] = [] private var poll: TelegramMediaPoll? @@ -996,7 +1024,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } - var previousOptionNodeLayouts: [Data: (_ contet: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode)))] = [:] + var previousOptionNodeLayouts: [Data: (_ contet: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ translation: TranslationMessageAttribute.Additional?, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode)))] = [:] for optionNode in self.optionNodes { if let option = optionNode.option { previousOptionNodeLayouts[option.opaqueIdentifier] = ChatMessagePollOptionNode.asyncLayout(optionNode) @@ -1115,26 +1143,40 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { let messageTheme = incoming ? item.presentationData.theme.theme.chat.message.incoming : item.presentationData.theme.theme.chat.message.outgoing - let attributedText: NSAttributedString - if let poll { - attributedText = stringWithAppliedEntities( - poll.text, - entities: poll.textEntities, - baseColor: messageTheme.primaryTextColor, - linkColor: messageTheme.linkTextColor, - baseFont: item.presentationData.messageBoldFont, - linkFont: item.presentationData.messageBoldFont, - boldFont: item.presentationData.messageBoldFont, - italicFont: item.presentationData.messageBoldFont, - boldItalicFont: item.presentationData.messageBoldFont, - fixedFont: item.presentationData.messageBoldFont, - blockQuoteFont: item.presentationData.messageBoldFont, - message: message - ) - } else { - attributedText = NSAttributedString(string: "", font: item.presentationData.messageBoldFont, textColor: messageTheme.primaryTextColor) + + var pollTitleText = poll?.text ?? "" + var pollTitleEntities = poll?.textEntities ?? [] + var pollOptions: [TranslationMessageAttribute.Additional] = [] + + var isTranslating = false + if let poll, let translateToLanguage = item.associatedData.translateToLanguage, !poll.text.isEmpty && incoming { + isTranslating = true + for attribute in item.message.attributes { + if let attribute = attribute as? TranslationMessageAttribute, !attribute.text.isEmpty, attribute.toLang == translateToLanguage { + pollTitleText = attribute.text + pollTitleEntities = attribute.entities + pollOptions = attribute.additional + isTranslating = false + break + } + } } + let attributedText = stringWithAppliedEntities( + pollTitleText, + entities: pollTitleEntities, + baseColor: messageTheme.primaryTextColor, + linkColor: messageTheme.linkTextColor, + baseFont: item.presentationData.messageBoldFont, + linkFont: item.presentationData.messageBoldFont, + boldFont: item.presentationData.messageBoldFont, + italicFont: item.presentationData.messageBoldFont, + boldItalicFont: item.presentationData.messageBoldFont, + fixedFont: item.presentationData.messageBoldFont, + blockQuoteFont: item.presentationData.messageBoldFont, + message: message + ) + let textInsets = UIEdgeInsets(top: 2.0, left: 0.0, bottom: 5.0, right: 0.0) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets)) @@ -1270,7 +1312,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { for i in 0 ..< poll.options.count { let option = poll.options[i] - let makeLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode))) + let makeLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ poll: TelegramMediaPoll, _ option: TelegramMediaPollOption, _ translation: TranslationMessageAttribute.Additional?, _ optionResult: ChatMessagePollOptionResult?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool, Bool) -> ChatMessagePollOptionNode))) if let previous = previousOptionNodeLayouts[option.opaqueIdentifier] { makeLayout = previous } else { @@ -1286,7 +1328,13 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } else if isClosed { optionResult = ChatMessagePollOptionResult(normalized: 0, percent: 0, count: 0) } - let result = makeLayout(item.context, item.presentationData, item.message, poll, option, optionResult, constrainedSize.width - layoutConstants.bubble.borderInset * 2.0) + + var translation: TranslationMessageAttribute.Additional? + if !pollOptions.isEmpty && i < pollOptions.count { + translation = pollOptions[i] + } + + let result = makeLayout(item.context, item.presentationData, item.message, poll, option, translation, optionResult, constrainedSize.width - layoutConstants.bubble.borderInset * 2.0) boundingSize.width = max(boundingSize.width, result.minimumWidth + layoutConstants.bubble.borderInset * 2.0) pollOptionsFinalizeLayouts.append(result.1) } @@ -1352,6 +1400,26 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.item = item strongSelf.poll = poll + let cachedLayout = strongSelf.textNode.textNode.cachedLayout + if case .System = animation { + if let cachedLayout = cachedLayout { + if !cachedLayout.areLinesEqual(to: textLayout) { + if let textContents = strongSelf.textNode.textNode.contents { + let fadeNode = ASDisplayNode() + fadeNode.displaysAsynchronously = false + fadeNode.contents = textContents + fadeNode.frame = strongSelf.textNode.textNode.frame + fadeNode.isLayerBacked = true + strongSelf.addSubnode(fadeNode) + fadeNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak fadeNode] _ in + fadeNode?.removeFromSupernode() + }) + strongSelf.textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) + } + } + } + } + let _ = textApply(TextNodeWithEntities.Arguments( context: item.context, cache: item.context.animationCache, @@ -1372,6 +1440,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } let optionNode = apply(animation.isAnimated, isRequesting, synchronousLoad) + let optionNodeFrame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) if optionNode.supernode !== strongSelf { strongSelf.addSubnode(optionNode) let option = optionNode.option @@ -1388,8 +1457,11 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } strongSelf.updateSelection() } + optionNode.frame = optionNodeFrame + } else { + animation.animator.updateFrame(layer: optionNode.layer, frame: optionNodeFrame, completion: nil) } - optionNode.frame = CGRect(origin: CGPoint(x: layoutConstants.bubble.borderInset, y: verticalOffset), size: size) + verticalOffset += size.height updatedOptionNodes.append(optionNode) optionNode.isUserInteractionEnabled = canVote && item.controllerInteraction.pollActionState.pollMessageIdsInProgress[item.message.id] == nil @@ -1411,7 +1483,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.textNode.textNode.frame = textFrame } let typeFrame = CGRect(origin: CGPoint(x: textFrame.minX, y: textFrame.maxY + titleTypeSpacing), size: typeLayout.size) - strongSelf.typeNode.frame = typeFrame + animation.animator.updateFrame(layer: strongSelf.typeNode.layer, frame: typeFrame, completion: nil) let deadlineTimeout = poll?.deadlineTimeout var displayDeadline = true @@ -1537,7 +1609,8 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { let _ = votersApply() let votersFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - votersLayout.size.width) / 2.0), y: verticalOffset + optionsVotersSpacing), size: votersLayout.size) - strongSelf.votersNode.frame = votersFrame + animation.animator.updateFrame(layer: strongSelf.votersNode.layer, frame: votersFrame, completion: nil) + if animation.isAnimated, let previousPoll = previousPoll, let poll = poll { if previousPoll.results.totalVoters == nil && poll.results.totalVoters != nil { strongSelf.votersNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) @@ -1572,6 +1645,8 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { strongSelf.updateSelection() strongSelf.updatePollTooltipMessageState(animated: false) + + strongSelf.updateIsTranslating(isTranslating) } }) }) @@ -1579,6 +1654,46 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } + private func updateIsTranslating(_ isTranslating: Bool) { + guard let item = self.item else { + return + } + var rects: [[CGRect]] = [] + let titleRects = (self.textNode.textNode.rangeRects(in: NSRange(location: 0, length: self.textNode.textNode.cachedLayout?.attributedString?.length ?? 0))?.rects ?? []).map { self.textNode.textNode.view.convert($0, to: self.view) } + rects.append(titleRects) + + for optionNode in self.optionNodes { + if let titleNode = optionNode.titleNode { + let optionRects = (titleNode.textNode.rangeRects(in: NSRange(location: 0, length: titleNode.textNode.cachedLayout?.attributedString?.length ?? 0))?.rects ?? []).map { titleNode.textNode.view.convert($0, to: self.view) } + rects.append(optionRects) + } + } + + if isTranslating, !rects.isEmpty { + if self.shimmeringNodes.isEmpty { + for rects in rects { + let shimmeringNode = ShimmeringLinkNode(color: item.message.effectivelyIncoming(item.context.account.peerId) ? item.presentationData.theme.theme.chat.message.incoming.secondaryTextColor.withAlphaComponent(0.1) : item.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor.withAlphaComponent(0.1)) + shimmeringNode.updateRects(rects) + shimmeringNode.frame = self.bounds + shimmeringNode.updateLayout(self.bounds.size) + shimmeringNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + self.shimmeringNodes.append(shimmeringNode) + self.insertSubnode(shimmeringNode, belowSubnode: self.textNode.textNode) + } + } + } else if !self.shimmeringNodes.isEmpty { + let shimmeringNodes = self.shimmeringNodes + self.shimmeringNodes = [] + + for shimmeringNode in shimmeringNodes { + shimmeringNode.alpha = 0.0 + shimmeringNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak shimmeringNode] _ in + shimmeringNode?.removeFromSupernode() + }) + } + } + } + private func updateSelection() { guard let item = self.item, let poll = self.poll else { return diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift index b7a03af976..8c29fa309a 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift @@ -999,6 +999,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { }) } } + override public func updateTouchesAtPoint(_ point: CGPoint?) { if let item = self.item { var rects: [CGRect]? diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 5b6cc6e9ba..21a41be265 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1934,7 +1934,7 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL } } - if let cachedData = data.cachedData as? CachedChannelData, isCreator || cachedData.flags.contains(.canViewStats) { + if let cachedData = data.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) { items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStats, label: .none, text: presentationData.strings.Channel_Info_Stats, icon: UIImage(bundleImageName: "Chat/Info/StatsIcon"), action: { interaction.openStats(false) })) diff --git a/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift index 110d7b1671..f2ebe3a305 100644 --- a/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift +++ b/submodules/TelegramUI/Components/Settings/AutomaticBusinessMessageSetupScreen/Sources/QuickReplySetupScreen.swift @@ -547,18 +547,18 @@ final class QuickReplySetupScreenComponent: Component { } func openQuickReplyChat(shortcut: String?, shortcutId: Int32?) { - guard let component = self.component, let environment = self.environment else { - return - } - - if case let .select(completion) = component.mode { - if let shortcutId { - completion(shortcutId) - } + guard let component = self.component, let environment = self.environment, let controller = self.environment?.controller() as? QuickReplySetupScreen else { return } + + self.contentListNode?.clearHighlightAnimated(true) if let shortcut { + if let shortcutId, case let .select(completion) = component.mode { + completion(shortcutId) + return + } + let shortcutType: ChatQuickReplyShortcutType if shortcut == "hello" { shortcutType = .greeting @@ -581,7 +581,12 @@ final class QuickReplySetupScreenComponent: Component { mode: .standard(.default) ) chatController.navigationPresentation = .modal - self.environment?.controller()?.push(chatController) + + if controller.navigationController != nil { + controller.push(chatController) + } else if let attachmentContainer = controller.parentController() { + attachmentContainer.push(chatController) + } } else { var completion: ((String?) -> Void)? let alertController = quickReplyNameAlertController( @@ -619,8 +624,6 @@ final class QuickReplySetupScreenComponent: Component { } self.environment?.controller()?.present(alertController, in: .window(.root)) } - - self.contentListNode?.clearHighlightAnimated(true) } func openEditShortcut(id: Int32, currentValue: String) { @@ -1172,13 +1175,8 @@ final class QuickReplySetupScreenComponent: Component { var entries: [ContentEntry] = [] if let shortcutMessageList = self.shortcutMessageList, let accountPeer = self.accountPeer { - switch component.mode { - case .manage: - if self.searchQuery.isEmpty { - entries.append(.add) - } - case .select: - break + if self.searchQuery.isEmpty { + entries.append(.add) } for item in shortcutMessageList.items { if !self.searchQuery.isEmpty { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 3618def914..3b495e571a 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -2711,6 +2711,10 @@ final class StoryItemSetContainerSendMessage { if let navigationController = controller.navigationController as? NavigationController { component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: component.context, chatLocation: .peer(peerId), attachBotStart: attachBotStart)) } + case let .withBotApp(botAppStart): + if let navigationController = controller.navigationController as? NavigationController { + component.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: component.context, chatLocation: .peer(peerId), botAppStart: botAppStart)) + } default: break } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 84eb599a98..4f32378a3b 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -2478,22 +2478,30 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto guard message.adAttribute == nil && message.id.namespace == Namespaces.Message.Cloud else { continue } - if !message.text.isEmpty && message.author?.id != self.context.account.peerId { - if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { - } else { - messageIdsToTranslate.append(message.id) - } + guard message.author?.id != self.context.account.peerId else { + continue + } + if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { + continue + } + if !message.text.isEmpty { + messageIdsToTranslate.append(message.id) + } else if let _ = message.media.first(where: { $0 is TelegramMediaPoll }) { + messageIdsToTranslate.append(message.id) } case let .MessageGroupEntry(_, messages, _): for (message, _, _, _, _) in messages { guard message.adAttribute == nil && message.id.namespace == Namespaces.Message.Cloud else { continue } - if !message.text.isEmpty && message.author?.id != self.context.account.peerId { - if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { - } else { - messageIdsToTranslate.append(message.id) - } + guard message.author?.id != self.context.account.peerId else { + continue + } + if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { + continue + } + if !message.text.isEmpty { + messageIdsToTranslate.append(message.id) } } default: diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index 606b23013b..f2b5dce928 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -126,13 +126,22 @@ public func translateMessageIds(context: AccountContext, messageIds: [EngineMess } } } - if !message.text.isEmpty && message.author?.id != context.account.peerId { - if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == toLang { - } else { - if !messageIdsSet.contains(messageId) { - messageIdsToTranslate.append(messageId) - messageIdsSet.insert(messageId) - } + guard message.author?.id != context.account.peerId else { + continue + } + if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == toLang { + continue + } + + if !message.text.isEmpty { + if !messageIdsSet.contains(messageId) { + messageIdsToTranslate.append(messageId) + messageIdsSet.insert(messageId) + } + } else if let _ = message.media.first(where: { $0 is TelegramMediaPoll }) { + if !messageIdsSet.contains(messageId) { + messageIdsToTranslate.append(messageId) + messageIdsSet.insert(messageId) } } } else {