From e11c9899e63f71ebd75986b792eb94a1b7754574 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 23 Mar 2026 15:03:50 +0100 Subject: [PATCH] Various fixes --- .../Sources/Node/ChatListItem.swift | 3 + .../Sources/Node/ChatListItemStrings.swift | 4 +- .../Sources/LegacyMediaPickerGallery.swift | 2 + .../SyncCore/SyncCore_TelegramMediaFile.swift | 4 + .../Sources/AttachmentFileController.swift | 2 + .../Sources/AttachmentFileSearchItem.swift | 15 +-- .../ChatMessageInteractiveMediaNode.swift | 7 +- .../ChatMessagePollBubbleContentNode.swift | 100 +++++++++++------- .../Sources/ComposePollScreen.swift | 2 + 9 files changed, 88 insertions(+), 51 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index b4efbf9c0b..911b55d7bc 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2686,6 +2686,9 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { return false } } + if let _ = message.media.first(where: { $0 is TelegramMediaPoll }) { + entities = [] + } if message.id.peerId.isTelegramNotifications || message.id.peerId.isVerificationCodes { let regex: NSRegularExpression? diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 523dee3445..889e737b7b 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -396,11 +396,9 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: } case let poll as TelegramMediaPoll: messageText = poll.text + customEmojiRanges = [] for entity in poll.textEntities { if case let .CustomEmoji(_, fileId) = entity.type { - if customEmojiRanges == nil { - customEmojiRanges = [] - } let range = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound) let attribute = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: message.associatedMedia[EngineMedia.Id(namespace: Namespaces.Media.CloudFile, id: fileId)] as? TelegramMediaFile) customEmojiRanges?.append((range, attribute)) diff --git a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift index 432770270f..cd635f88cc 100644 --- a/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift +++ b/submodules/MediaPickerUI/Sources/LegacyMediaPickerGallery.swift @@ -148,6 +148,8 @@ func presentLegacyMediaPickerGallery( paintStickersContext.livePhotoButton = { if case .secretChat = peer { return nil + } else if peer == nil { + return nil } let livePhotoButton = LivePhotoButton() livePhotoButton.present = present diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift index 05fd50a8a7..c999ba735b 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift @@ -1343,6 +1343,10 @@ public final class TelegramMediaFile: Media, Equatable, Codable { public func withUpdatedVideoCover(_ videoCover: TelegramMediaImage?) -> TelegramMediaFile { return TelegramMediaFile(fileId: self.fileId, partialReference: self.partialReference, resource: self.resource, previewRepresentations: self.previewRepresentations, videoThumbnails: self.videoThumbnails, videoCover: videoCover, immediateThumbnailData: self.immediateThumbnailData, mimeType: self.mimeType, size: self.size, attributes: self.attributes, alternativeRepresentations: self.alternativeRepresentations) } + + public func withUpdatedImmediateThumnailData(_ immediateThumbnailData: Data?) -> TelegramMediaFile { + return TelegramMediaFile(fileId: self.fileId, partialReference: self.partialReference, resource: self.resource, previewRepresentations: self.previewRepresentations, videoThumbnails: self.videoThumbnails, videoCover: self.videoCover, immediateThumbnailData: immediateThumbnailData, mimeType: self.mimeType, size: self.size, attributes: self.attributes, alternativeRepresentations: self.alternativeRepresentations) + } } public func ==(lhs: TelegramMediaFile, rhs: TelegramMediaFile) -> Bool { diff --git a/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileController.swift b/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileController.swift index 89de1295a7..c8fc718326 100644 --- a/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileController.swift +++ b/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileController.swift @@ -919,6 +919,8 @@ public func makeAttachmentFileControllerImpl( arguments.send(message) }, dismissInput: { dismissInputImpl?() + }, didPreviewAudio: { + didPreviewAudio = true }) } diff --git a/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileSearchItem.swift b/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileSearchItem.swift index cd46f98d27..a179d739f1 100644 --- a/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileSearchItem.swift +++ b/submodules/TelegramUI/Components/AttachmentFileController/Sources/AttachmentFileSearchItem.swift @@ -32,12 +32,13 @@ final class AttachmentFileSearchItem: ItemListControllerSearch { let cancel: () -> Void let send: (Message) -> Void let dismissInput: () -> Void + let didPreviewAudio: () -> Void private var updateActivity: ((Bool) -> Void)? private var activity: ValuePromise = ValuePromise(ignoreRepeated: false) private let activityDisposable = MetaDisposable() - init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, focus: @escaping () -> Void, cancel: @escaping () -> Void, send: @escaping (Message) -> Void, dismissInput: @escaping () -> Void) { + init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, focus: @escaping () -> Void, cancel: @escaping () -> Void, send: @escaping (Message) -> Void, dismissInput: @escaping () -> Void, didPreviewAudio: @escaping () -> Void) { self.context = context self.mode = mode self.presentationData = presentationData @@ -45,6 +46,7 @@ final class AttachmentFileSearchItem: ItemListControllerSearch { self.cancel = cancel self.send = send self.dismissInput = dismissInput + self.didPreviewAudio = didPreviewAudio self.activityDisposable.set((activity.get() |> mapToSignal { value -> Signal in if value { return .single(value) |> delay(0.2, queue: Queue.mainQueue()) @@ -89,7 +91,7 @@ final class AttachmentFileSearchItem: ItemListControllerSearch { func node(current: ItemListControllerSearchNode?, titleContentNode: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> ItemListControllerSearchNode { return AttachmentFileSearchItemNode(context: self.context, mode: self.mode, presentationData: self.presentationData, focus: self.focus, send: self.send, cancel: self.cancel, updateActivity: { [weak self] value in self?.activity.set(value) - }, dismissInput: self.dismissInput) + }, dismissInput: self.dismissInput, didPreviewAudio: self.didPreviewAudio) } } @@ -106,7 +108,7 @@ private final class AttachmentFileSearchItemNode: ItemListControllerSearchNode { private var validLayout: ContainerViewLayout? - init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, focus: @escaping () -> Void, send: @escaping (Message) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, dismissInput: @escaping () -> Void) { + init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, focus: @escaping () -> Void, send: @escaping (Message) -> Void, cancel: @escaping () -> Void, updateActivity: @escaping(Bool) -> Void, dismissInput: @escaping () -> Void, didPreviewAudio: @escaping () -> Void) { self.context = context self.mode = mode self.presentationData = presentationData @@ -115,7 +117,7 @@ private final class AttachmentFileSearchItemNode: ItemListControllerSearchNode { self.containerNode = AttachmentFileSearchContainerNode(context: context, mode: mode, presentationData: presentationData, send: { message in send(message) - }, updateActivity: updateActivity) + }, updateActivity: updateActivity, didPreviewAudio: didPreviewAudio) super.init() @@ -413,7 +415,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon return _hasDim } - public init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, send: @escaping (Message) -> Void, updateActivity: @escaping (Bool) -> Void) { + public init(context: AccountContext, mode: AttachmentFileControllerMode, presentationData: PresentationData, send: @escaping (Message) -> Void, updateActivity: @escaping (Bool) -> Void, didPreviewAudio: @escaping () -> Void) { self.context = context self.send = send @@ -476,7 +478,6 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon self.addSubnode(self.emptyResultsTitleNode) self.addSubnode(self.emptyResultsTextNode) - let interaction = AttachmentFileSearchContainerInteraction( context: context, send: { [weak self] message in @@ -484,6 +485,8 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon self?.listNode.clearHighlightAnimated(true) }, toggleMediaPlayback: { message in + didPreviewAudio() + let playlistLocation: PeerMessagesPlaylistLocation = .custom(messages: .single(([message], 0, false)), canReorder: false, at: message.id, loadMore: nil, hidePanel: true) context.sharedContext.mediaManager.setPlaylist((context, PeerMessagesMediaPlaylist(context: context, location: playlistLocation, chatLocationContextHolder: nil)), type: .music, control: .playback(.togglePlayPause)) }, diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift index 44ce39c4ef..9f9796ea95 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift @@ -1511,7 +1511,12 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr } }) - effectiveFile = image.video + if var video = image.video { + if video.immediateThumbnailData == nil { + video = video.withUpdatedImmediateThumnailData(image.immediateThumbnailData) + } + effectiveFile = video + } } else if let image = media as? TelegramMediaWebFile { if hasCurrentVideoNode { replaceVideoNode = true diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift index 2ded096d5a..cd3a777d1b 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift @@ -835,7 +835,26 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { // } let rightInset: CGFloat = 10.0 + mediaInset - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: optionAttributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: max(1.0, constrainedWidth - leftInset - rightInset), height: CGFloat.greatestFiniteMagnitude), alignment: .left, cutout: nil, insets: UIEdgeInsets(top: 1.0, left: 0.0, bottom: 1.0, right: 0.0))) + let recentVoterPeers: [Peer] + if let optionResult { + recentVoterPeers = optionResult.recentVoterPeerIds.compactMap { message.peers[$0] } + } else { + recentVoterPeers = [] + } + + var titleTrailingInset = rightInset + if let countImage = updatedCountImage ?? maybeNode?.countImage, displayCount { + titleTrailingInset += countImage.size.width + ChatMessagePollOptionNode.countSpacing + } + if !recentVoterPeers.isEmpty { + var avatarsReservedWidth = ChatMessagePollOptionNode.avatarsSize.width - 15.0 + ChatMessagePollOptionNode.avatarsSpacing + if recentVoterPeers.count > 1 { + avatarsReservedWidth += 15.0 + } + titleTrailingInset += avatarsReservedWidth + } + + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: optionAttributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: max(1.0, constrainedWidth - leftInset - titleTrailingInset), height: CGFloat.greatestFiniteMagnitude), alignment: .left, cutout: nil, insets: UIEdgeInsets(top: 1.0, left: 0.0, bottom: 1.0, right: 0.0))) let contentLayoutHeight: CGFloat = max(52.0, titleLayout.size.height + 28.0) let contentHeight: CGFloat = contentLayoutHeight + (optionResult != nil ? 7.0 : 0.0) @@ -915,7 +934,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { } } - return (titleLayout.size.width + leftInset + rightInset, { width in + return (titleLayout.size.width + leftInset + titleTrailingInset, { width in return (CGSize(width: width, height: contentHeight), { animated, inProgress, attemptSynchronous in let node: ChatMessagePollOptionNode if let maybeNode = maybeNode { @@ -970,7 +989,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { )) let titleNodeFrame: CGRect if titleLayout.hasRTL { - titleNodeFrame = CGRect(origin: CGPoint(x: width - rightInset - titleLayout.size.width, y: 15.0), size: titleLayout.size) + titleNodeFrame = CGRect(origin: CGPoint(x: width - titleTrailingInset - titleLayout.size.width, y: 15.0), size: titleLayout.size) } else { titleNodeFrame = CGRect(origin: CGPoint(x: leftInset, y: 15.0), size: titleLayout.size) } @@ -1042,13 +1061,6 @@ private final class ChatMessagePollOptionNode: ASDisplayNode { node.countImage = updatedCountImage } - let recentVoterPeers: [Peer] - if let optionResult { - recentVoterPeers = optionResult.recentVoterPeerIds.compactMap { message.peers[$0] } - } else { - recentVoterPeers = [] - } - var trailingOriginX = width - rightInset let mediaFrame: CGRect? @@ -1449,7 +1461,7 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { fontSize: font.pointSize, textColor: currentTextColor, accentColor: currentTintColor, - insets: UIEdgeInsets(top: ChatMessagePollAddOptionNode.verticalInset, left: 0.0, bottom: ChatMessagePollAddOptionNode.verticalInset, right: 0.0), + insets: UIEdgeInsets(top: ChatMessagePollAddOptionNode.verticalInset, left: 8.0, bottom: ChatMessagePollAddOptionNode.verticalInset, right: 8.0), hideKeyboard: self.currentFocusedTextInputIsMedia, customInputView: nil, placeholder: NSAttributedString(string: strings.CreatePoll_AddOption, font: font, textColor: currentPlaceholderColor), @@ -1476,10 +1488,9 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { ) } - @discardableResult - private func updateTextFieldLayout(size: CGSize, forceUpdate: Bool) -> CGSize { + private func updateTextFieldLayout(size: CGSize, forceUpdate: Bool) { guard let component = self.makeTextFieldComponent() else { - return CGSize(width: self.currentTextWidth, height: max(ChatMessagePollAddOptionNode.minHeight, size.height)) + return } let textFieldSize = self.textField.update( @@ -1487,32 +1498,34 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { component: AnyComponent(component), environment: {}, forceUpdate: forceUpdate, - containerSize: CGSize(width: self.currentTextWidth, height: 1000.0) + containerSize: CGSize(width: self.currentTextWidth + 16.0, height: 1000.0) ) if let textFieldView = self.textField.view { if textFieldView.superview == nil { self.view.insertSubview(textFieldView, belowSubview: self.leftAccessoryButton.view) } - textFieldView.frame = CGRect(origin: CGPoint(x: ChatMessagePollAddOptionNode.leftInset - 8.0, y: 0.0), size: CGSize(width: textFieldSize.width, height: size.height)) + textFieldView.frame = CGRect(origin: CGPoint(x: ChatMessagePollAddOptionNode.leftInset - 16.0, y: 0.0), size: CGSize(width: textFieldSize.width, height: size.height)) } - - return textFieldSize } private func handleTextFieldStateUpdated(transition: ComponentTransition) { - guard let secondaryTextColor = self.currentSecondaryTextColor, !self.currentSize.width.isZero else { + guard let secondaryTextColor = self.currentSecondaryTextColor, let font = self.currentFont, !self.currentSize.width.isZero else { return } + let updatedText = self._textFieldExternalState.text + let updatedMetrics = ChatMessagePollAddOptionNode.layoutMetrics(constrainedWidth: self.currentSize.width, text: updatedText, attachment: self.currentAttachment, font: font) + let previousText = self.currentTextValue let previousIsEditing = self.currentIsEditing let previousMeasuredHeight = self.currentMeasuredHeight ?? self.currentSize.height - let textFieldSize = self.updateTextFieldLayout(size: self.currentSize, forceUpdate: true) - let updatedText = self._textFieldExternalState.text + self.currentTextWidth = updatedMetrics.textWidth + self.updateTextFieldLayout(size: self.currentSize, forceUpdate: true) + let updatedIsEditing = self.textFieldView?.isActive ?? self._textFieldExternalState.isEditing - let updatedMeasuredHeight = max(ChatMessagePollAddOptionNode.minHeight, textFieldSize.height) + let updatedMeasuredHeight = updatedMetrics.contentHeight self.currentTextValue = updatedText self.currentIsEditing = updatedIsEditing @@ -1532,8 +1545,12 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { self.updateAttachmentLayout(size: self.currentSize, tintColor: secondaryTextColor) } - private static func measureContentHeight(text: String, font: UIFont, textWidth: CGFloat) -> CGFloat { - var measureText = text + private static func layoutMetrics(constrainedWidth: CGFloat, text: NSAttributedString, attachment: Attachment?, font: UIFont) -> (textWidth: CGFloat, contentHeight: CGFloat) { + let constrainedWidth = min(268.0, constrainedWidth) + let hasTrailingAccessory = attachment?.media != nil || !text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + let textWidth = max(1.0, constrainedWidth - ChatMessagePollAddOptionNode.leftInset - ChatMessagePollAddOptionNode.rightInset - (hasTrailingAccessory ? ChatMessagePollAddOptionNode.attachmentInset : 0.0)) + + var measureText = text.string if measureText.hasSuffix("\n") || measureText.isEmpty { measureText += "|" } @@ -1541,7 +1558,11 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { measureTextNode.maximumNumberOfLines = 0 measureTextNode.attributedText = NSAttributedString(string: measureText, font: font, textColor: .black) let measureSize = measureTextNode.updateLayout(CGSize(width: textWidth, height: .greatestFiniteMagnitude)) - return max(ChatMessagePollAddOptionNode.minHeight, measureSize.height + ChatMessagePollAddOptionNode.verticalInset * 2.0) + + return ( + textWidth: textWidth, + contentHeight: max(ChatMessagePollAddOptionNode.minHeight, measureSize.height + ChatMessagePollAddOptionNode.verticalInset * 2.0) + ) } static func asyncLayout(_ maybeNode: ChatMessagePollAddOptionNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ strings: PresentationStrings, _ incoming: Bool, _ focusedTextInputIsMedia: Bool, _ text: NSAttributedString, _ attachment: Attachment?, _ constrainedWidth: CGFloat) -> (minimumWidth: CGFloat, layout: ((CGFloat) -> (CGSize, (Bool, Bool) -> ChatMessagePollAddOptionNode))) { @@ -1552,14 +1573,11 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { let placeholderColor = (incoming ? presentationData.theme.theme.chat.message.incoming.secondaryTextColor : presentationData.theme.theme.chat.message.outgoing.secondaryTextColor).withMultipliedAlpha(0.7) let tintColor = incoming ? presentationData.theme.theme.chat.message.incoming.polls.bar : presentationData.theme.theme.chat.message.outgoing.polls.bar - let hasAttachmentPreview = attachment?.media != nil - let displayAttachButton = !text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !hasAttachmentPreview let constrainedWidth = min(268.0, constrainedWidth) - let textWidth = max(1.0, constrainedWidth - ChatMessagePollAddOptionNode.leftInset - ChatMessagePollAddOptionNode.rightInset - (hasAttachmentPreview || displayAttachButton ? ChatMessagePollAddOptionNode.attachmentInset : 0.0)) - let contentHeight = ChatMessagePollAddOptionNode.measureContentHeight(text: text.string, font: font, textWidth: textWidth) + let metrics = ChatMessagePollAddOptionNode.layoutMetrics(constrainedWidth: constrainedWidth, text: text, attachment: attachment, font: font) return (constrainedWidth, { width in - let size = CGSize(width: width, height: contentHeight) + let size = CGSize(width: width, height: metrics.contentHeight) return (size, { _, _ in let node = maybeNode ?? ChatMessagePollAddOptionNode() @@ -1573,20 +1591,20 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { node.addIconNode.image = generateTintedImage(image: PresentationResourcesChat.chatPollAddIcon(presentationData.theme.theme), color: secondaryTextColor.withMultipliedAlpha(0.7)) } - node.currentTextWidth = textWidth + node.currentTextWidth = metrics.textWidth node.currentSize = size node.currentAttachment = attachment node.currentContext = context node.currentTheme = presentationData.theme.theme node.currentIncoming = incoming node.currentFocusedTextInputIsMedia = focusedTextInputIsMedia - let textFieldSize = node.updateTextFieldLayout(size: size, forceUpdate: false) - node.currentMeasuredHeight = max(ChatMessagePollAddOptionNode.minHeight, textFieldSize.height) - node.currentTextValue = node._textFieldExternalState.text + node.updateTextFieldLayout(size: size, forceUpdate: false) + node.currentMeasuredHeight = metrics.contentHeight + node.currentTextValue = text node.currentIsEditing = node.textFieldView?.isActive ?? node._textFieldExternalState.isEditing - node.leftAccessoryButton.frame = CGRect(origin: .zero, size: CGSize(width: ChatMessagePollAddOptionNode.leftInset, height: contentHeight)) - node.separatorNode.frame = CGRect(origin: CGPoint(x: ChatMessagePollAddOptionNode.leftInset, y: contentHeight - UIScreenPixel), size: CGSize(width: width - ChatMessagePollAddOptionNode.leftInset - 10.0, height: UIScreenPixel)) + node.leftAccessoryButton.frame = CGRect(origin: .zero, size: CGSize(width: ChatMessagePollAddOptionNode.leftInset, height: size.height)) + node.separatorNode.frame = CGRect(origin: CGPoint(x: ChatMessagePollAddOptionNode.leftInset, y: size.height - UIScreenPixel), size: CGSize(width: width - ChatMessagePollAddOptionNode.leftInset - 10.0, height: UIScreenPixel)) node.separatorNode.backgroundColor = incoming ? presentationData.theme.theme.chat.message.incoming.polls.separator : presentationData.theme.theme.chat.message.outgoing.polls.separator node.updateModeSelectorLayout(size: size, theme: presentationData.theme.theme, animated: false) node.updateAttachmentLayout(size: size, tintColor: secondaryTextColor) @@ -1691,7 +1709,7 @@ private final class ChatMessagePollAddOptionNode: ASDisplayNode { let imageNodeSize = CGSize(width: 40.0, height: 40.0) let imageNodeFrame = CGRect(origin: CGPoint(x: size.width - 10.0 - imageNodeSize.width, y: size.height - ChatMessagePollAddOptionNode.minHeight + floor((ChatMessagePollAddOptionNode.minHeight - imageNodeSize.height) * 0.5)), size: imageNodeSize) - let shouldShowAttachButton = self.currentAttachment?.media == nil && self.text.length != 0 + let shouldShowAttachButton = self.currentAttachment?.media == nil && !self.text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty if shouldShowAttachButton { let attachButton: HighlightableButtonNode if let current = self.attachButton { @@ -2318,7 +2336,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } - let canAlwaysViewResults = poll.isCreator + let canAlwaysViewResults = poll.isCreator if !hasSelection || (canAlwaysViewResults && selectedOpaqueIdentifiers.isEmpty) { if !Namespaces.Message.allNonRegular.contains(item.message.id.namespace) { switch poll.publicity { @@ -2746,7 +2764,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { } } - boundingSize.width = max(boundingSize.width, min(270.0, constrainedSize.width)) + boundingSize.width = max(boundingSize.width, min(280.0, constrainedSize.width)) var canVote = false if (item.message.id.namespace == Namespaces.Message.Cloud || Namespaces.Message.allNonRegular.contains(item.message.id.namespace)), let poll = poll, poll.pollId.namespace == Namespaces.Media.CloudPoll, !isClosed { @@ -3182,8 +3200,8 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { buttonWidth = strongSelf.buttonSaveTextNode.frame.width } else if !strongSelf.buttonViewResultsTextNode.isHidden { buttonWidth = strongSelf.buttonViewResultsTextNode.frame.width - } else if !strongSelf.buttonSubmitActiveTextNode.isHidden { - buttonWidth = strongSelf.buttonSubmitActiveTextNode.frame.width + } else if !strongSelf.buttonSubmitActiveTextNode.isHidden || !strongSelf.buttonSubmitInactiveTextNode.isHidden { + buttonWidth = max(strongSelf.buttonSubmitActiveTextNode.frame.width, strongSelf.buttonSubmitInactiveTextNode.frame.width) } buttonWidth = floor(buttonWidth * 1.1) strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: floor((resultSize.width - buttonWidth) / 2.0), y: verticalOffset), size: CGSize(width: buttonWidth, height: 44.0)) diff --git a/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift b/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift index a0b6138a18..27f028ad3a 100644 --- a/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift +++ b/submodules/TelegramUI/Components/ComposePollScreen/Sources/ComposePollScreen.swift @@ -849,6 +849,8 @@ final class ComposePollScreenComponent: Component { return } + self.endEditing(true) + guard replace || !self.openAttachMediaContextMenu(subject: subject) else { return }