From c17cedf49427fdd7c63f3db5822ea949080798c2 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 9 Sep 2020 22:37:40 +0100 Subject: [PATCH] Comment updates --- .../TelegramUI/Sources/ChatController.swift | 5 + .../ChatInterfaceStateContextMenus.swift | 16 ++- .../ChatInterfaceStateNavigationButtons.swift | 18 +-- .../ChatMessageAttachedContentNode.swift | 2 +- .../Sources/ChatMessageBubbleItemNode.swift | 107 +++++++++++------- .../ChatMessageCommentFooterContentNode.swift | 19 ++-- .../ChatMessageContactBubbleContentNode.swift | 2 +- .../ChatMessageFileBubbleContentNode.swift | 2 +- .../ChatMessageMapBubbleContentNode.swift | 2 +- .../ChatMessageMediaBubbleContentNode.swift | 2 +- .../ChatMessagePollBubbleContentNode.swift | 2 +- ...atMessageRestrictedBubbleContentNode.swift | 2 +- .../ChatMessageTextBubbleContentNode.swift | 16 +-- .../TelegramUI/Sources/ChatTitleView.swift | 4 + 14 files changed, 122 insertions(+), 77 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 6e53d483ab..67090daf54 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -8346,6 +8346,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.loadingMessage.set(false) } })) + } else { + if let navigationController = self.effectiveNavigationController { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message($0) })) + } + completion?() } } } else { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 2d8ba2f370..b96d8a447a 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -297,7 +297,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: let message = messages[0] - if Namespaces.Message.allScheduled.contains(message.id.namespace) { + if Namespaces.Message.allScheduled.contains(message.id.namespace) || message.id.peerId.isReplies { canReply = false canPin = false } else if messages[0].flags.intersection([.Failed, .Unsent]).isEmpty { @@ -758,7 +758,15 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: UIPasteboard.general.string = link let presentationData = context.sharedContext.currentPresentationData.with { $0 } - if channel.addressName == nil { + + var warnAboutPrivate = false + if case let .peer = chatPresentationInterfaceState.chatLocation { + if channel.addressName == nil { + warnAboutPrivate = true + } + } + + if warnAboutPrivate { controllerInteraction.presentGlobalOverlayController(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Conversation_PrivateMessageLinkCopied, true)), nil) } else { controllerInteraction.presentGlobalOverlayController(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.GroupInfo_InviteLink_CopyAlert_Success, false)), nil) @@ -1050,7 +1058,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me } } } else if let user = peer as? TelegramUser { - if !isScheduled && message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction { + if !isScheduled && message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction && !message.id.peerId.isReplies { if !(message.flags.isSending || message.flags.contains(.Failed)) { optionsMap[id]!.insert(.forward) } @@ -1073,7 +1081,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me if canDeleteGlobally { optionsMap[id]!.insert(.deleteGlobally) } - if user.botInfo != nil { + if user.botInfo != nil && !user.id.isReplies { optionsMap[id]!.insert(.report) } } else if let _ = peer as? TelegramSecretChat { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift index 54794ece85..a8971c99a5 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateNavigationButtons.swift @@ -27,6 +27,9 @@ struct ChatNavigationButton: Equatable { func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, subject: ChatControllerSubject?, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?) -> ChatNavigationButton? { if let _ = presentationInterfaceState.interfaceState.selectionState { + if case .replyThread = presentationInterfaceState.chatLocation { + return nil + } if let currentButton = currentButton, currentButton.action == .clearHistory { return currentButton } else if let peer = presentationInterfaceState.renderedPeer?.peer { @@ -64,6 +67,14 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha } func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? { + if let _ = presentationInterfaceState.interfaceState.selectionState { + if let currentButton = currentButton, currentButton.action == .cancelMessageSelection { + return currentButton + } else { + return ChatNavigationButton(action: .cancelMessageSelection, buttonItem: UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: target, action: selector)) + } + } + if case .replyThread = presentationInterfaceState.chatLocation { if case .search = currentButton?.action { return currentButton @@ -84,13 +95,6 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch } } } - if let _ = presentationInterfaceState.interfaceState.selectionState { - if let currentButton = currentButton, currentButton.action == .cancelMessageSelection { - return currentButton - } else { - return ChatNavigationButton(action: .cancelMessageSelection, buttonItem: UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: target, action: selector)) - } - } if presentationInterfaceState.isScheduledMessages { return chatInfoNavigationButton diff --git a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift index c41cd908d9..f1e12efd59 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAttachedContentNode.swift @@ -531,7 +531,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { var additionalImageBadgeContent: ChatMessageInteractiveMediaBadgeContent? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): let imageMode = !((refineContentImageLayout == nil && refineContentFileLayout == nil && contentInstantVideoSizeAndApply == nil) || preferMediaBeforeText) statusInText = !imageMode diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index ce41155605..0e5911be0d 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -29,8 +29,13 @@ enum InternalBubbleTapAction { case openContextMenu(tapMessage: Message, selectAll: Bool, subFrame: CGRect) } -private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass, ChatMessageEntryAttributes, Bool)] { - var result: [(Message, AnyClass, ChatMessageEntryAttributes, Bool)] = [] +private struct BubbleItemAttributes { + var isAttachment: Bool + var neighborType: ChatMessageBubbleRelativePosition.NeighbourType +} + +private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] { + var result: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] = [] var skipText = false var messageWithCaptionToAdd: (Message, ChatMessageEntryAttributes)? var isUnsupportedMedia = false @@ -39,46 +44,46 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [( outer: for (message, itemAttributes) in item.content { for attribute in message.attributes { if let attribute = attribute as? RestrictedContentMessageAttribute, attribute.platformText(platform: "ios", contentSettings: item.context.currentContentSettings.with { $0 }) != nil { - result.append((message, ChatMessageRestrictedBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageRestrictedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) break outer } } inner: for media in message.media { if let _ = media as? TelegramMediaImage { - result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true)) + result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media))) } else if let file = media as? TelegramMediaFile { let isVideo = file.isVideo || (file.isAnimated && file.dimensions != nil) if isVideo { - result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true)) + result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media))) } else { - result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } } else if let action = media as? TelegramMediaAction { isAction = true if case .phoneCall = action.action { - result.append((message, ChatMessageCallBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageCallBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } else { - result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } } else if let _ = media as? TelegramMediaMap { - result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, true)) + result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media))) } else if let _ = media as? TelegramMediaGame { skipText = true - result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) break inner } else if let _ = media as? TelegramMediaInvoice { skipText = true - result.append((message, ChatMessageInvoiceBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageInvoiceBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) break inner } else if let _ = media as? TelegramMediaContact { - result.append((message, ChatMessageContactBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageContactBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } else if let _ = media as? TelegramMediaExpiredContent { result.removeAll() - result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) return result } else if let _ = media as? TelegramMediaPoll { - result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } else if let _ = media as? TelegramMediaUnsupported { isUnsupportedMedia = true } @@ -95,7 +100,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [( messageWithCaptionToAdd = (message, itemAttributes) skipText = true } else { - result.append((message, ChatMessageTextBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } } else { if case .group = item.content { @@ -107,34 +112,34 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [( inner: for media in message.media { if let webpage = media as? TelegramMediaWebpage { if case .Loaded = webpage.content { - result.append((message, ChatMessageWebpageBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageWebpageBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } break inner } } if isUnsupportedMedia { - result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, false)) + result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } } if let (messageWithCaptionToAdd, itemAttributes) = messageWithCaptionToAdd { - result.append((messageWithCaptionToAdd, ChatMessageTextBubbleContentNode.self, itemAttributes, false)) + result.append((messageWithCaptionToAdd, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } if let additionalContent = item.additionalContent { switch additionalContent { case let .eventLogPreviousMessage(previousMessage): - result.append((previousMessage, ChatMessageEventLogPreviousMessageContentNode.self, ChatMessageEntryAttributes(), false)) + result.append((previousMessage, ChatMessageEventLogPreviousMessageContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) case let .eventLogPreviousDescription(previousMessage): - result.append((previousMessage, ChatMessageEventLogPreviousDescriptionContentNode.self, ChatMessageEntryAttributes(), false)) + result.append((previousMessage, ChatMessageEventLogPreviousDescriptionContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) case let .eventLogPreviousLink(previousMessage): - result.append((previousMessage, ChatMessageEventLogPreviousLinkContentNode.self, ChatMessageEntryAttributes(), false)) + result.append((previousMessage, ChatMessageEventLogPreviousLinkContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform))) } } let firstMessage = item.content.firstMessage - if !isAction { + if !isAction && !Namespaces.Message.allScheduled.contains(firstMessage.id.namespace) { var hasDiscussion = false if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) { hasDiscussion = true @@ -159,10 +164,10 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [( } if canComment { - result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), false)) + result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform))) } } else if firstMessage.id.peerId.isReplies { - result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), false)) + result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform))) } } @@ -981,22 +986,22 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset) - var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = [] + var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, BubbleItemAttributes, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = [] var addedContentNodes: [(Message, ChatMessageBubbleContentNode)]? let contentNodeMessagesAndClasses = contentNodeMessagesAndClassesForItem(item) - for (contentNodeMessage, contentNodeClass, attributes, isAttachment) in contentNodeMessagesAndClasses { + for (contentNodeMessage, contentNodeClass, attributes, bubbleAttributes) in contentNodeMessagesAndClasses { var found = false for (currentMessage, currentClass, supportsMosaic, currentLayout) in currentContentClassesPropertiesAndLayouts { if currentClass == contentNodeClass && currentMessage.stableId == contentNodeMessage.stableId { - contentPropertiesAndPrepareLayouts.append((contentNodeMessage, supportsMosaic, attributes, isAttachment, currentLayout)) + contentPropertiesAndPrepareLayouts.append((contentNodeMessage, supportsMosaic, attributes, bubbleAttributes, currentLayout)) found = true break } } if !found { let contentNode = (contentNodeClass as! ChatMessageBubbleContentNode.Type).init() - contentPropertiesAndPrepareLayouts.append((contentNodeMessage, contentNode.supportsMosaic, attributes, isAttachment, contentNode.asyncLayoutContent())) + contentPropertiesAndPrepareLayouts.append((contentNodeMessage, contentNode.supportsMosaic, attributes, bubbleAttributes, contentNode.asyncLayoutContent())) if addedContentNodes == nil { addedContentNodes = [] } @@ -1052,7 +1057,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode inlineBotNameString = nil } - var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, Bool, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = [] + var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, BubbleItemAttributes, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = [] let topNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedTop.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing) let bottomNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedBottom.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing) @@ -1100,16 +1105,21 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode } var index = 0 - for (message, _, attributes, isAttachment, prepareLayout) in contentPropertiesAndPrepareLayouts { + for (message, _, attributes, bubbleAttributes, prepareLayout) in contentPropertiesAndPrepareLayouts { let topPosition: ChatMessageBubbleRelativePosition let bottomPosition: ChatMessageBubbleRelativePosition - if index != 0 && contentPropertiesAndPrepareLayouts[index - 1].3 { - topPosition = .Neighbour(true, .freeform) - } else { - topPosition = .Neighbour(false, .freeform) + var topBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform) + var bottomBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform) + if index != 0 { + topBubbleAttributes = contentPropertiesAndPrepareLayouts[index - 1].3 } - bottomPosition = .Neighbour(false, .freeform) + if index != contentPropertiesAndPrepareLayouts.count - 1 { + bottomBubbleAttributes = contentPropertiesAndPrepareLayouts[index + 1].3 + } + + topPosition = .Neighbour(topBubbleAttributes.isAttachment, topBubbleAttributes.neighborType) + bottomPosition = .Neighbour(bottomBubbleAttributes.isAttachment, bottomBubbleAttributes.neighborType) let prepareContentPosition: ChatMessageBubblePreparePosition if let mosaicRange = mosaicRange, mosaicRange.contains(index) { @@ -1118,7 +1128,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode let refinedBottomPosition: ChatMessageBubbleRelativePosition if index == contentPropertiesAndPrepareLayouts.count - 1 { refinedBottomPosition = .None(.Left) - } else if index == contentPropertiesAndPrepareLayouts.count - 2 && contentPropertiesAndPrepareLayouts[contentPropertiesAndPrepareLayouts.count - 1].3 { + } else if index == contentPropertiesAndPrepareLayouts.count - 2 && contentPropertiesAndPrepareLayouts[contentPropertiesAndPrepareLayouts.count - 1].3.isAttachment { refinedBottomPosition = .None(.Left) } else { refinedBottomPosition = bottomPosition @@ -1151,7 +1161,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(contentItem, layoutConstants, prepareContentPosition, itemSelection, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude)) maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth) - contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, isAttachment, nodeLayout)) + contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, bubbleAttributes, nodeLayout)) switch properties.hidesBackground { case .never: @@ -1266,7 +1276,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode maximumNodeWidth = size.width - if mosaicRange.upperBound == contentPropertiesAndLayouts.count { + if mosaicRange.upperBound == contentPropertiesAndLayouts.count || contentPropertiesAndLayouts[contentPropertiesAndLayouts.count - 1].3.isAttachment { let message = item.content.firstMessage var edited = false @@ -1601,19 +1611,26 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode case .linear: let topPosition: ChatMessageBubbleRelativePosition let bottomPosition: ChatMessageBubbleRelativePosition + + var topBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform) + var bottomBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform) + if i != 0 { + topBubbleAttributes = contentPropertiesAndLayouts[i - 1].3 + } + if i != contentPropertiesAndLayouts.count - 1 { + bottomBubbleAttributes = contentPropertiesAndLayouts[i + 1].3 + } if i == 0 { topPosition = firstNodeTopPosition - } else if i == contentNodeCount - 1 && i != 0 && contentPropertiesAndLayouts[i - 1].3 { - topPosition = .Neighbour(true, .freeform) } else { - topPosition = .Neighbour(false, .freeform) + topPosition = .Neighbour(topBubbleAttributes.isAttachment, topBubbleAttributes.neighborType) } if i == contentNodeCount - 1 { bottomPosition = lastNodeTopPosition } else { - bottomPosition = .Neighbour(false, .freeform) + bottomPosition = .Neighbour(bottomBubbleAttributes.isAttachment, bottomBubbleAttributes.neighborType) } contentPosition = .linear(top: topPosition, bottom: bottomPosition) @@ -1832,7 +1849,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode replyInfoOriginY: CGFloat, removedContentNodeIndices: [Int]?, addedContentNodes: [(Message, ChatMessageBubbleContentNode)]?, - contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, Bool)], + contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)], contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, (ListViewItemUpdateAnimation, Bool) -> Void)], mosaicStatusOrigin: CGPoint?, mosaicStatusSizeAndApply: (CGSize, (Bool) -> ChatMessageDateAndStatusNode)?, @@ -2475,8 +2492,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { navigate = .chat(textInputState: nil, subject: nil, peekData: nil) - } else { + } else if openPeerId.namespace == Namespaces.Peer.CloudUser { navigate = .info + } else { + navigate = .chat(textInputState: nil, subject: nil, peekData: nil) } for attribute in item.content.firstMessage.attributes { diff --git a/submodules/TelegramUI/Sources/ChatMessageCommentFooterContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageCommentFooterContentNode.swift index adeee93afd..143fc08019 100644 --- a/submodules/TelegramUI/Sources/ChatMessageCommentFooterContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageCommentFooterContentNode.swift @@ -100,10 +100,13 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let displaySeparator: Bool - if case let .linear(top, _) = preparePosition, case .Neighbour(true, _) = top { + let topOffset: CGFloat + if case let .linear(top, _) = preparePosition, case .Neighbour(_, .media) = top { displaySeparator = false + topOffset = 2.0 } else { displaySeparator = true + topOffset = 0.0 } return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in @@ -163,7 +166,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets, lineColor: messageTheme.accentControlColor)) - var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0), size: textLayout.size) + var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0 + topOffset), size: textLayout.size) var textFrameWithoutInsets = CGRect(origin: CGPoint(x: textFrame.origin.x + textInsets.left, y: textFrame.origin.y + textInsets.top), size: CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom)) textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top - 5.0 + UIScreenPixel) @@ -189,7 +192,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { boundingSize = textFrameWithoutInsets.size boundingSize.width += layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right - boundingSize.height = 40.0 + boundingSize.height = 40.0 + topOffset return (boundingSize, { [weak self] animation, synchronousLoad in if let strongSelf = self { @@ -225,17 +228,17 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { if let iconImage = iconImage { strongSelf.iconNode.image = iconImage - strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 15.0 + iconOffset.x, y: 6.0 + iconOffset.y), size: iconImage.size) + strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 15.0 + iconOffset.x, y: 6.0 + iconOffset.y + topOffset), size: iconImage.size) } if let arrowImage = arrowImage { strongSelf.arrowNode.image = arrowImage - strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 33.0, y: 6.0), size: arrowImage.size) + strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 33.0, y: 6.0 + topOffset), size: arrowImage.size) } strongSelf.iconNode.isHidden = !replyPeers.isEmpty - let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: 3.0), size: CGSize(width: imageSize * 3.0, height: imageSize)) + let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: 3.0 + topOffset), size: CGSize(width: imageSize * 3.0, height: imageSize)) strongSelf.avatarsNode.frame = avatarsFrame strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size) strongSelf.avatarsNode.update(context: item.context, peers: replyPeers, synchronousLoad: synchronousLoad, imageSize: imageSize, imageSpacing: imageSpacing, borderWidth: 2.0 - UIScreenPixel) @@ -245,6 +248,8 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: layoutConstants.bubble.strokeInsets.left, y: -3.0), size: CGSize(width: boundingWidth - layoutConstants.bubble.strokeInsets.left - layoutConstants.bubble.strokeInsets.right, height: UIScreenPixel)) strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: boundingWidth, height: boundingSize.height)) + + strongSelf.buttonNode.isUserInteractionEnabled = item.message.id.namespace == Namespaces.Message.Cloud } }) }) @@ -276,7 +281,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if self.buttonNode.frame.contains(point) { + if self.buttonNode.isUserInteractionEnabled && self.buttonNode.frame.contains(point) { return self.buttonNode.view } return nil diff --git a/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift index 6bfef25e69..4f63c7c143 100644 --- a/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageContactBubbleContentNode.swift @@ -176,7 +176,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if item.message.effectivelyIncoming(item.context.account.peerId) { statusType = .BubbleIncoming } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift index d05a91106a..dc0198b6de 100644 --- a/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageFileBubbleContentNode.swift @@ -69,7 +69,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode { let incoming = item.message.effectivelyIncoming(item.context.account.peerId) let statusType: ChatMessageDateAndStatusType? switch preparePosition { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if incoming { statusType = .BubbleIncoming } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift index aa1148e2cd..6440354556 100644 --- a/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageMapBubbleContentNode.swift @@ -212,7 +212,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if selectedMedia?.venue != nil || activeLiveBroadcastingTimeout != nil { if item.message.effectivelyIncoming(item.context.account.peerId) { statusType = .BubbleIncoming diff --git a/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift index 3fbace1ef7..ebaf889c65 100644 --- a/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageMediaBubbleContentNode.swift @@ -207,7 +207,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if item.message.effectivelyIncoming(item.context.account.peerId) { statusType = .ImageIncoming } else { diff --git a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift index 2668adcf64..721e616c3d 100644 --- a/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessagePollBubbleContentNode.swift @@ -1054,7 +1054,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if incoming { statusType = .BubbleIncoming } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift index 4abd2baa5a..b10af32878 100644 --- a/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageRestrictedBubbleContentNode.swift @@ -85,7 +85,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? switch position { - case .linear(_, .None): + case .linear(_, .None), .linear(_, .Neighbour(true, _)): if incoming { statusType = .BubbleIncoming } else { diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 330a36366c..f21468cb52 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -140,14 +140,14 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { let statusType: ChatMessageDateAndStatusType? var displayStatus = false switch position { - case let .linear(_, neighbor): - if case .None = neighbor { - displayStatus = true - } else if case .Neighbour(true, _) = neighbor { - displayStatus = true - } - default: - break + case let .linear(_, neighbor): + if case .None = neighbor { + displayStatus = true + } else if case .Neighbour(true, _) = neighbor { + displayStatus = true + } + default: + break } if displayStatus { if incoming { diff --git a/submodules/TelegramUI/Sources/ChatTitleView.swift b/submodules/TelegramUI/Sources/ChatTitleView.swift index e302cd7d0d..4dafec51f7 100644 --- a/submodules/TelegramUI/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Sources/ChatTitleView.swift @@ -203,6 +203,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.setNeedsLayout() } self.isUserInteractionEnabled = isEnabled + self.button.isUserInteractionEnabled = isEnabled self.updateStatus() } } @@ -635,6 +636,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if !self.isUserInteractionEnabled { + return nil + } if self.button.frame.contains(point) { return self.button.view }