Various fixes

This commit is contained in:
Ilya Laktyushin 2022-10-23 08:15:11 +03:00
parent 0bf8b373e3
commit e090872d2f
27 changed files with 465 additions and 87 deletions

View File

@ -148,12 +148,12 @@ class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode {
return mediaHidden return mediaHidden
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeLabelLayout = TextNodeWithEntities.asyncLayout(self.labelNode) let makeLabelLayout = TextNodeWithEntities.asyncLayout(self.labelNode)
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center)
let backgroundImage = PresentationResourcesChat.chatActionPhotoBackgroundImage(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty) let backgroundImage = PresentationResourcesChat.chatActionPhotoBackgroundImage(item.presentationData.theme.theme, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)

View File

@ -531,7 +531,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
} else if file.isInstantVideo { } else if file.isInstantVideo {
let displaySize = CGSize(width: 212.0, height: 212.0) let displaySize = CGSize(width: 212.0, height: 212.0)
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file) let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file)
let (videoLayout, apply) = contentInstantVideoLayout(ChatMessageBubbleContentItem(context: context, controllerInteraction: controllerInteraction, message: message, topMessage: message, read: messageRead, chatLocation: chatLocation, presentationData: presentationData, associatedData: associatedData, attributes: attributes, isItemPinned: message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), constrainedSize.width - horizontalInsets.left - horizontalInsets.right, displaySize, displaySize, 0.0, .bubble, automaticDownload) let (videoLayout, apply) = contentInstantVideoLayout(ChatMessageBubbleContentItem(context: context, controllerInteraction: controllerInteraction, message: message, topMessage: message, read: messageRead, chatLocation: chatLocation, presentationData: presentationData, associatedData: associatedData, attributes: attributes, isItemPinned: message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), constrainedSize.width - horizontalInsets.left - horizontalInsets.right, displaySize, displaySize, 0.0, .bubble, automaticDownload, 0.0)
initialWidth = videoLayout.contentSize.width + videoLayout.overflowLeft + videoLayout.overflowRight initialWidth = videoLayout.contentSize.width + videoLayout.overflowLeft + videoLayout.overflowRight
contentInstantVideoSizeAndApply = (videoLayout, apply) contentInstantVideoSizeAndApply = (videoLayout, apply)
} else if file.isVideo { } else if file.isVideo {

View File

@ -28,6 +28,7 @@ struct ChatMessageBubbleContentProperties {
let forceAlignment: ChatMessageBubbleContentAlignment let forceAlignment: ChatMessageBubbleContentAlignment
let shareButtonOffset: CGPoint? let shareButtonOffset: CGPoint?
let hidesHeaders: Bool let hidesHeaders: Bool
let avatarOffset: CGFloat?
init( init(
hidesSimpleAuthorHeader: Bool, hidesSimpleAuthorHeader: Bool,
@ -36,7 +37,8 @@ struct ChatMessageBubbleContentProperties {
forceFullCorners: Bool, forceFullCorners: Bool,
forceAlignment: ChatMessageBubbleContentAlignment, forceAlignment: ChatMessageBubbleContentAlignment,
shareButtonOffset: CGPoint? = nil, shareButtonOffset: CGPoint? = nil,
hidesHeaders: Bool = false hidesHeaders: Bool = false,
avatarOffset: CGFloat? = nil
) { ) {
self.hidesSimpleAuthorHeader = hidesSimpleAuthorHeader self.hidesSimpleAuthorHeader = hidesSimpleAuthorHeader
self.headerSpacing = headerSpacing self.headerSpacing = headerSpacing
@ -45,6 +47,7 @@ struct ChatMessageBubbleContentProperties {
self.forceAlignment = forceAlignment self.forceAlignment = forceAlignment
self.shareButtonOffset = shareButtonOffset self.shareButtonOffset = shareButtonOffset
self.hidesHeaders = hidesHeaders self.hidesHeaders = hidesHeaders
self.avatarOffset = avatarOffset
} }
} }
@ -172,7 +175,7 @@ class ChatMessageBubbleContentNode: ASDisplayNode {
super.init() super.init()
} }
func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
preconditionFailure() preconditionFailure()
} }

View File

@ -1039,7 +1039,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) { override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = [] var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = []
for contentNode in self.contentNodes { for contentNode in self.contentNodes {
if let message = contentNode.item?.message { if let message = contentNode.item?.message {
currentContentClassesPropertiesAndLayouts.append((message, type(of: contentNode) as AnyClass, contentNode.supportsMosaic, contentNode.asyncLayoutContent())) currentContentClassesPropertiesAndLayouts.append((message, type(of: contentNode) as AnyClass, contentNode.supportsMosaic, contentNode.asyncLayoutContent()))
@ -1086,7 +1086,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
private static func beginLayout(selfReference: Weak<ChatMessageBubbleItemNode>, _ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool, private static func beginLayout(selfReference: Weak<ChatMessageBubbleItemNode>, _ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool,
currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))], currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))],
authorNameLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode), authorNameLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode), adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode), forwardInfoLayout: (ChatPresentationData, PresentationStrings, ChatMessageForwardInfoType, Peer?, String?, String?, CGSize) -> (CGSize, (CGFloat) -> ChatMessageForwardInfoNode),
@ -1135,7 +1135,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
var displayAuthorInfo: Bool var displayAuthorInfo: Bool
var ignoreNameHiding = false var ignoreNameHiding = false
let avatarInset: CGFloat var avatarInset: CGFloat
var hasAvatar = false var hasAvatar = false
var allowFullWidth = false var allowFullWidth = false
@ -1348,14 +1348,14 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
} }
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, ListViewItemApply?) -> Void))))] = [] var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, BubbleItemAttributes, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = []
var addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]? var addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]?
for contentNodeItemValue in contentNodeMessagesAndClasses { for contentNodeItemValue in contentNodeMessagesAndClasses {
let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes) let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes)
var found = false var found = false
for currentNodeItemValue in currentContentClassesPropertiesAndLayouts { for currentNodeItemValue in currentContentClassesPropertiesAndLayouts {
let currentNodeItem = currentNodeItemValue as (message: Message, type: AnyClass, supportsMosaic: Bool, currentLayout: (ChatMessageBubbleContentItem, ChatMessageItemLayoutConstants, ChatMessageBubblePreparePosition, Bool?, CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)))) let currentNodeItem = currentNodeItemValue as (message: Message, type: AnyClass, supportsMosaic: Bool, currentLayout: (ChatMessageBubbleContentItem, ChatMessageItemLayoutConstants, ChatMessageBubblePreparePosition, Bool?, CGSize, CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))
if currentNodeItem.type == contentNodeItem.type && currentNodeItem.message.stableId == contentNodeItem.message.stableId { if currentNodeItem.type == contentNodeItem.type && currentNodeItem.message.stableId == contentNodeItem.message.stableId {
contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, currentNodeItem.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, currentNodeItem.currentLayout)) contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, currentNodeItem.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, currentNodeItem.currentLayout))
@ -1529,6 +1529,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
var hidesHeaders = false var hidesHeaders = false
var shareButtonOffset: CGPoint? var shareButtonOffset: CGPoint?
var avatarOffset: CGFloat?
var index = 0 var index = 0
for (message, _, attributes, bubbleAttributes, prepareLayout) in contentPropertiesAndPrepareLayouts { for (message, _, attributes, bubbleAttributes, prepareLayout) in contentPropertiesAndPrepareLayouts {
let topPosition: ChatMessageBubbleRelativePosition let topPosition: ChatMessageBubbleRelativePosition
@ -1581,7 +1582,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
} }
let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(contentItem, layoutConstants, prepareContentPosition, itemSelection, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude)) let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(contentItem, layoutConstants, prepareContentPosition, itemSelection, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), avatarInset)
maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth) maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth)
if let offset = properties.shareButtonOffset { if let offset = properties.shareButtonOffset {
@ -1590,6 +1591,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
if properties.hidesHeaders { if properties.hidesHeaders {
hidesHeaders = true hidesHeaders = true
} }
if let offset = properties.avatarOffset {
avatarOffset = offset
if !offset.isZero {
avatarInset = 0.0
}
}
contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, bubbleAttributes, nodeLayout, needSeparateContainers && !bubbleAttributes.isAttachment ? message.stableId : nil, itemSelection)) contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, bubbleAttributes, nodeLayout, needSeparateContainers && !bubbleAttributes.isAttachment ? message.stableId : nil, itemSelection))
@ -2385,6 +2392,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
mosaicStatusSizeAndApply: mosaicStatusSizeAndApply, mosaicStatusSizeAndApply: mosaicStatusSizeAndApply,
needsShareButton: needsShareButton, needsShareButton: needsShareButton,
shareButtonOffset: shareButtonOffset, shareButtonOffset: shareButtonOffset,
avatarOffset: avatarOffset,
hidesHeaders: hidesHeaders hidesHeaders: hidesHeaders
) )
}) })
@ -2431,6 +2439,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
mosaicStatusSizeAndApply: (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode)?, mosaicStatusSizeAndApply: (CGSize, (ListViewItemUpdateAnimation) -> ChatMessageDateAndStatusNode)?,
needsShareButton: Bool, needsShareButton: Bool,
shareButtonOffset: CGPoint?, shareButtonOffset: CGPoint?,
avatarOffset: CGFloat?,
hidesHeaders: Bool hidesHeaders: Bool
) -> Void { ) -> Void {
guard let strongSelf = selfReference.value else { guard let strongSelf = selfReference.value else {
@ -2489,6 +2498,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
strongSelf.backgroundNode.backgroundFrame = backgroundFrame strongSelf.backgroundNode.backgroundFrame = backgroundFrame
if let avatarOffset = avatarOffset {
strongSelf.updateAttachedAvatarNodeOffset(offset: avatarOffset, transition: .animated(duration: 0.3, curve: .spring))
}
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp()) let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
if isFailed { if isFailed {
let deliveryFailedNode: ChatMessageDeliveryFailedNode let deliveryFailedNode: ChatMessageDeliveryFailedNode
@ -2691,6 +2704,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
animateFrame = false animateFrame = false
replyInfoNode.visibility = strongSelf.visibility != .none replyInfoNode.visibility = strongSelf.visibility != .none
if animation.isAnimated {
replyInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
} }
let previousReplyInfoNodeFrame = replyInfoNode.frame let previousReplyInfoNodeFrame = replyInfoNode.frame
replyInfoNode.frame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + replyInfoOriginY), size: replyInfoSizeApply.0) replyInfoNode.frame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + replyInfoOriginY), size: replyInfoSizeApply.0)
@ -2700,8 +2717,17 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
} }
} }
} else { } else {
strongSelf.replyInfoNode?.removeFromSupernode() if animation.isAnimated {
strongSelf.replyInfoNode = nil if let replyInfoNode = strongSelf.replyInfoNode {
strongSelf.replyInfoNode = nil
replyInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak replyInfoNode] _ in
replyInfoNode?.removeFromSupernode()
})
}
} else {
strongSelf.replyInfoNode?.removeFromSupernode()
strongSelf.replyInfoNode = nil
}
} }
var incomingOffset: CGFloat = 0.0 var incomingOffset: CGFloat = 0.0

View File

@ -62,11 +62,11 @@ class ChatMessageCallBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeLabelLayout = TextNode.asyncLayout(self.labelNode) let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in
let incoming = item.message.effectivelyIncoming(item.context.account.peerId) let incoming = item.message.effectivelyIncoming(item.context.account.peerId)

View File

@ -96,11 +96,11 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
} }
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeCountLayout = self.countNode.asyncLayout() let makeCountLayout = self.countNode.asyncLayout()
let makeAlternativeCountLayout = self.alternativeCountNode.asyncLayout() let makeAlternativeCountLayout = self.alternativeCountNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
let displaySeparator: Bool let displaySeparator: Bool

View File

@ -75,7 +75,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
self.view.addGestureRecognizer(tapRecognizer) self.view.addGestureRecognizer(tapRecognizer)
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let statusLayout = self.dateAndStatusNode.asyncLayout() let statusLayout = self.dateAndStatusNode.asyncLayout()
let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeTextLayout = TextNode.asyncLayout(self.textNode) let makeTextLayout = TextNode.asyncLayout(self.textNode)
@ -84,7 +84,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
let previousContact = self.contact let previousContact = self.contact
let previousContactInfo = self.contactInfo let previousContactInfo = self.contactInfo
return { item, layoutConstants, _, _, constrainedSize in return { item, layoutConstants, _, _, constrainedSize, _ in
var selectedContact: TelegramMediaContact? var selectedContact: TelegramMediaContact?
for media in item.message.media { for media in item.message.media {
if let media = media as? TelegramMediaContact { if let media = media as? TelegramMediaContact {

View File

@ -27,10 +27,10 @@ final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessageBubble
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var messageEntities: [MessageTextEntity]? var messageEntities: [MessageTextEntity]?
for attribute in item.message.attributes { for attribute in item.message.attributes {

View File

@ -27,10 +27,10 @@ final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubbleContent
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var messageEntities: [MessageTextEntity]? var messageEntities: [MessageTextEntity]?
for attribute in item.message.attributes { for attribute in item.message.attributes {

View File

@ -27,10 +27,10 @@ final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBubbleCont
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var messageEntities: [MessageTextEntity]? var messageEntities: [MessageTextEntity]?
for attribute in item.message.attributes { for attribute in item.message.attributes {

View File

@ -91,10 +91,10 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let interactiveFileLayout = self.interactiveFileNode.asyncLayout() let interactiveFileLayout = self.interactiveFileNode.asyncLayout()
return { item, layoutConstants, preparePosition, selection, constrainedSize in return { item, layoutConstants, preparePosition, selection, constrainedSize, _ in
var selectedFile: TelegramMediaFile? var selectedFile: TelegramMediaFile?
for media in item.message.media { for media in item.message.media {
if let telegramFile = media as? TelegramMediaFile { if let telegramFile = media as? TelegramMediaFile {

View File

@ -41,10 +41,10 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var game: TelegramMediaGame? var game: TelegramMediaGame?
var messageEntities: [MessageTextEntity]? var messageEntities: [MessageTextEntity]?

View File

@ -137,7 +137,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let _ = item.controllerInteraction.openMessage(item.message, .default) let _ = item.controllerInteraction.openMessage(item.message, .default)
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeLabelLayout = TextNode.asyncLayout(self.labelNode) let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
let makeTitleLayout = TextNode.asyncLayout(self.titleNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
let makeSubtitleLayout = TextNode.asyncLayout(self.subtitleNode) let makeSubtitleLayout = TextNode.asyncLayout(self.subtitleNode)
@ -145,7 +145,7 @@ class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in

View File

@ -29,16 +29,29 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
if case .visible = oldValue { if case .visible = oldValue {
wasVisible = true wasVisible = true
} }
var isVisible = false let isVisible = self.isContentVisible
if case .visible = self.visibility {
isVisible = true
}
if wasVisible != isVisible { if wasVisible != isVisible {
self.interactiveVideoNode.visibility = isVisible if !isVisible {
Queue.mainQueue().after(0.05) {
if isVisible == self.isContentVisible {
self.interactiveVideoNode.visibility = isVisible
}
}
} else {
self.interactiveVideoNode.visibility = isVisible
}
} }
} }
} }
private var isContentVisible: Bool {
var isVisible = false
if case .visible = self.visibility {
isVisible = true
}
return isVisible
}
required init() { required init() {
self.interactiveFileNode = ChatMessageInteractiveFileNode() self.interactiveFileNode = ChatMessageInteractiveFileNode()
self.interactiveVideoNode = ChatMessageInteractiveInstantVideoNode() self.interactiveVideoNode = ChatMessageInteractiveInstantVideoNode()
@ -134,7 +147,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let interactiveVideoLayout = self.interactiveVideoNode.asyncLayout() let interactiveVideoLayout = self.interactiveVideoNode.asyncLayout()
let interactiveFileLayout = self.interactiveFileNode.asyncLayout() let interactiveFileLayout = self.interactiveFileNode.asyncLayout()
@ -142,7 +155,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
let audioTranscriptionState = self.audioTranscriptionState let audioTranscriptionState = self.audioTranscriptionState
let didSetupFileNode = self.item != nil let didSetupFileNode = self.item != nil
return { item, layoutConstants, preparePosition, selection, constrainedSize in return { item, layoutConstants, preparePosition, selection, constrainedSize, avatarInset in
var selectedFile: TelegramMediaFile? var selectedFile: TelegramMediaFile?
for media in item.message.media { for media in item.message.media {
if let telegramFile = media as? TelegramMediaFile { if let telegramFile = media as? TelegramMediaFile {
@ -198,9 +211,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
if case .replyThread = item.chatLocation { if case .replyThread = item.chatLocation {
isReplyThread = true isReplyThread = true
} }
let avatarInset: CGFloat = 0.0
var isExpanded = false var isExpanded = false
if case .expanded = audioTranscriptionState { if case .expanded = audioTranscriptionState {
isExpanded = true isExpanded = true
@ -210,23 +221,21 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
let normalDisplaySize = layoutConstants.instantVideo.dimensions let normalDisplaySize = layoutConstants.instantVideo.dimensions
var displaySize = normalDisplaySize var displaySize = normalDisplaySize
let maximumDisplaySize = CGSize(width: min(404, constrainedSize.width - 2.0), height: min(404, constrainedSize.width - 2.0)) let maximumDisplaySize = CGSize(width: min(404, constrainedSize.width - 2.0), height: min(404, constrainedSize.width - 2.0))
// var effectiveAvatarInset = avatarInset
if item.associatedData.currentlyPlayingMessageId == item.message.index { if item.associatedData.currentlyPlayingMessageId == item.message.index {
isPlaying = true isPlaying = true
if !isExpanded { if !isExpanded {
displaySize = maximumDisplaySize displaySize = maximumDisplaySize
} }
// effectiveAvatarInset = 0.0
} }
let leftInset: CGFloat = 0.0 let leftInset: CGFloat = 0.0
let rightInset: CGFloat = 0.0 let rightInset: CGFloat = 0.0
let (videoLayout, videoApply) = interactiveVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.message, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.attributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), constrainedSize.width - leftInset - rightInset - avatarInset, displaySize, maximumDisplaySize, isPlaying ? 1.0 : 0.0, .free, automaticDownload) let (videoLayout, videoApply) = interactiveVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.message, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.attributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), constrainedSize.width - leftInset - rightInset - avatarInset, displaySize, maximumDisplaySize, isPlaying ? 1.0 : 0.0, .free, automaticDownload, avatarInset)
let videoFrame = CGRect(origin: CGPoint(x: 1.0, y: 1.0), size: videoLayout.contentSize) let videoFrame = CGRect(origin: CGPoint(x: 1.0, y: 1.0), size: videoLayout.contentSize)
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none, shareButtonOffset: isExpanded ? .zero : CGPoint(x: -16.0, y: -24.0), hidesHeaders: !isExpanded) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none, shareButtonOffset: isExpanded ? .zero : CGPoint(x: -16.0, y: -24.0), hidesHeaders: !isExpanded, avatarOffset: !isExpanded && isPlaying ? -100.0 : 0.0)
let width = videoFrame.width + 2.0 let width = videoFrame.width + 2.0
@ -328,8 +337,10 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
} }
var videoAnimation = animation var videoAnimation = animation
var fileAnimation = animation
if currentExpanded != isExpanded { if currentExpanded != isExpanded {
videoAnimation = .None videoAnimation = .None
fileAnimation = .None
} }
animation.animator.updateFrame(layer: strongSelf.interactiveVideoNode.layer, frame: videoFrame, completion: nil) animation.animator.updateFrame(layer: strongSelf.interactiveVideoNode.layer, frame: videoFrame, completion: nil)
@ -337,7 +348,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
if let fileSize = finalFileSize { if let fileSize = finalFileSize {
strongSelf.interactiveFileNode.frame = CGRect(origin: CGPoint(x: layoutConstants.file.bubbleInsets.left, y: layoutConstants.file.bubbleInsets.top), size: fileSize) strongSelf.interactiveFileNode.frame = CGRect(origin: CGPoint(x: layoutConstants.file.bubbleInsets.left, y: layoutConstants.file.bubbleInsets.top), size: fileSize)
finalFileApply?(synchronousLoads, .None, applyInfo) finalFileApply?(synchronousLoads, fileAnimation, applyInfo)
} }
if currentExpanded != isExpanded { if currentExpanded != isExpanded {

View File

@ -389,7 +389,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
isReplyThread = true isReplyThread = true
} }
let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.content.firstMessage, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, maximumDisplaySize, isPlaying ? 1.0 : 0.0, .free, automaticDownload) let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.content.firstMessage, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, maximumDisplaySize, isPlaying ? 1.0 : 0.0, .free, automaticDownload, 0.0)
let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + effectiveAvatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize) let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + effectiveAvatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize)
@ -1264,7 +1264,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
effectiveAvatarInset *= (1.0 - scaleProgress) effectiveAvatarInset *= (1.0 - scaleProgress)
displaySize = CGSize(width: initialSize.width + (targetSize.width - initialSize.width) * animationProgress, height: initialSize.height + (targetSize.height - initialSize.height) * animationProgress) displaySize = CGSize(width: initialSize.width + (targetSize.width - initialSize.width) * animationProgress, height: initialSize.height + (targetSize.height - initialSize.height) * animationProgress)
let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.message, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, maximumDisplaySize, scaleProgress, .free, self.appliedAutomaticDownload) let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, topMessage: item.message, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes, isItemPinned: item.message.tags.contains(.pinned) && !isReplyThread, isItemEdited: false), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, maximumDisplaySize, scaleProgress, .free, self.appliedAutomaticDownload, 0.0)
let availableContentWidth = params.width - params.leftInset - params.rightInset - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left let availableContentWidth = params.width - params.leftInset - params.rightInset - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left
let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + effectiveAvatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize) let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + effectiveAvatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize)

View File

@ -143,7 +143,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
var audioTranscriptionButton: ComponentHostView<Empty>? var audioTranscriptionButton: ComponentHostView<Empty>?
private var transcriptionPendingIndicator: ComponentHostView<Empty>? private var transcriptionPendingIndicator: ComponentHostView<Empty>?
let textNode: TextNode let textNode: TextNode
private let textClippingNode: ASDisplayNode let textClippingNode: ASDisplayNode
private var textSelectionNode: TextSelectionNode? private var textSelectionNode: TextSelectionNode?
var updateIsTextSelectionActive: ((Bool) -> Void)? var updateIsTextSelectionActive: ((Bool) -> Void)?

View File

@ -17,6 +17,8 @@ import ComponentFlow
import AudioTranscriptionButtonComponent import AudioTranscriptionButtonComponent
import UndoUI import UndoUI
import TelegramNotices import TelegramNotices
import Markdown
import TextFormat
struct ChatMessageInstantVideoItemLayoutResult { struct ChatMessageInstantVideoItemLayoutResult {
let contentSize: CGSize let contentSize: CGSize
@ -30,6 +32,9 @@ enum ChatMessageInstantVideoItemLayoutData {
} }
private let textFont = Font.regular(11.0) private let textFont = Font.regular(11.0)
private let nameFont = Font.medium(14.0)
private let inlineBotPrefixFont = Font.regular(14.0)
private let inlineBotNameFont = nameFont
enum ChatMessageInteractiveInstantVideoNodeStatusType { enum ChatMessageInteractiveInstantVideoNodeStatusType {
case free case free
@ -48,9 +53,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
} }
var customIsHidden: Bool = false { var canAttachContent: Bool = false {
didSet { didSet {
if self.customIsHidden != oldValue { if self.canAttachContent != oldValue {
Queue.mainQueue().justDispatch { Queue.mainQueue().justDispatch {
self.videoNode?.canAttachContent = self.shouldAcquireVideoContext self.videoNode?.canAttachContent = self.shouldAcquireVideoContext
} }
@ -73,6 +78,8 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
private var item: ChatMessageBubbleContentItem? private var item: ChatMessageBubbleContentItem?
private var automaticDownload: Bool? private var automaticDownload: Bool?
var media: TelegramMediaFile? var media: TelegramMediaFile?
var appliedForwardInfo: (Peer?, String?)?
private var secretProgressIcon: UIImage? private var secretProgressIcon: UIImage?
private let fetchDisposable = MetaDisposable() private let fetchDisposable = MetaDisposable()
@ -84,6 +91,11 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
private let infoBackgroundNode: ASImageNode private let infoBackgroundNode: ASImageNode
private let muteIconNode: ASImageNode private let muteIconNode: ASImageNode
var viaBotNode: TextNode?
var replyInfoNode: ChatMessageReplyInfoNode?
var replyBackgroundNode: NavigationBackgroundNode?
var forwardInfoNode: ChatMessageForwardInfoNode?
private var status: FileMediaResourceStatus? private var status: FileMediaResourceStatus?
private var playerStatus: MediaPlayerStatus? { private var playerStatus: MediaPlayerStatus? {
didSet { didSet {
@ -97,7 +109,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
private let fetchedThumbnailDisposable = MetaDisposable() private let fetchedThumbnailDisposable = MetaDisposable()
private var shouldAcquireVideoContext: Bool { private var shouldAcquireVideoContext: Bool {
if self.visibility && self.trackingIsInHierarchy && !self.customIsHidden { if self.visibility && self.trackingIsInHierarchy && !self.canAttachContent {
return true return true
} else { } else {
return false return false
@ -195,10 +207,11 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
self.layer.addSublayer(hierarchyTrackingLayer) self.layer.addSublayer(hierarchyTrackingLayer)
} }
func asyncLayout() -> (_ item: ChatMessageBubbleContentItem, _ width: CGFloat, _ displaySize: CGSize, _ maximumDisplaySize: CGSize, _ scaleProgress: CGFloat, _ statusType: ChatMessageInteractiveInstantVideoNodeStatusType, _ automaticDownload: Bool) -> (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> Void) { func asyncLayout() -> (_ item: ChatMessageBubbleContentItem, _ width: CGFloat, _ displaySize: CGSize, _ maximumDisplaySize: CGSize, _ scaleProgress: CGFloat, _ statusType: ChatMessageInteractiveInstantVideoNodeStatusType, _ automaticDownload: Bool, _ avatarInset: CGFloat) -> (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> Void) {
let previousFile = self.media let previousFile = self.media
let currentItem = self.item let currentItem = self.item
let currentForwardInfo = self.appliedForwardInfo
let previousAutomaticDownload = self.automaticDownload let previousAutomaticDownload = self.automaticDownload
let makeDateAndStatusLayout = self.dateAndStatusNode.asyncLayout() let makeDateAndStatusLayout = self.dateAndStatusNode.asyncLayout()
@ -206,14 +219,22 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
let audioTranscriptionState = self.audioTranscriptionState let audioTranscriptionState = self.audioTranscriptionState
let audioTranscriptionText = self.audioTranscriptionText let audioTranscriptionText = self.audioTranscriptionText
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusDisplayType, automaticDownload in let viaBotLayout = TextNode.asyncLayout(self.viaBotNode)
let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode)
let makeForwardInfoLayout = ChatMessageForwardInfoNode.asyncLayout(self.forwardInfoNode)
let currentReplyBackgroundNode = self.replyBackgroundNode
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusDisplayType, automaticDownload, avatarInset in
var secretVideoPlaceholderBackgroundImage: UIImage? var secretVideoPlaceholderBackgroundImage: UIImage?
var updatedInfoBackgroundImage: UIImage? var updatedInfoBackgroundImage: UIImage?
var updatedMuteIconImage: UIImage? var updatedMuteIconImage: UIImage?
var viaBotApply: (TextNodeLayout, () -> TextNode)?
var replyInfoApply: (CGSize, (Bool) -> ChatMessageReplyInfoNode)?
var updatedReplyBackgroundNode: NavigationBackgroundNode?
var updatedInstantVideoBackgroundImage: UIImage? var updatedInstantVideoBackgroundImage: UIImage?
let instantVideoBackgroundImage: UIImage? let instantVideoBackgroundImage: UIImage?
switch statusDisplayType { switch statusDisplayType {
case .free: case .free:
instantVideoBackgroundImage = nil instantVideoBackgroundImage = nil
@ -260,6 +281,115 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
} }
var ignoreForward = false
var ignoreSource = false
if let forwardInfo = item.message.forwardInfo {
if !item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
for attribute in item.message.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute {
if attribute.messageId.peerId == forwardInfo.author?.id {
ignoreForward = true
} else {
ignoreSource = true
}
break
}
}
} else {
ignoreForward = true
}
}
let bubbleEdgeInset: CGFloat = 4.0
let bubbleContentInsetsLeft: CGFloat = 6.0
let availableWidth = max(60.0, width - 210.0 - bubbleEdgeInset * 2.0 - bubbleContentInsetsLeft - 20.0)
let availableContentWidth = width - bubbleEdgeInset * 2.0 - bubbleContentInsetsLeft - 20.0
for attribute in item.message.attributes {
if let attribute = attribute as? InlineBotMessageAttribute {
var inlineBotNameString: String?
if let peerId = attribute.peerId, let bot = item.message.peers[peerId] as? TelegramUser {
inlineBotNameString = bot.addressName
} else {
inlineBotNameString = attribute.title
}
if let inlineBotNameString = inlineBotNameString {
let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
let bodyAttributes = MarkdownAttributeSet(font: nameFont, textColor: inlineBotNameColor)
let boldAttributes = MarkdownAttributeSet(font: inlineBotPrefixFont, textColor: inlineBotNameColor)
let botString = addAttributesToStringWithRanges(item.presentationData.strings.Conversation_MessageViaUser("@\(inlineBotNameString)")._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: botString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
ignoreForward = true
}
}
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
} else {
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
presentationData: item.presentationData,
strings: item.presentationData.strings,
context: item.context,
type: .standalone,
message: replyMessage,
parentMessage: item.message,
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
))
}
}
}
if !ignoreSource, !item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
for attribute in item.message.attributes {
if let attribute = attribute as? SourceReferenceMessageAttribute {
if let sourcePeer = item.message.peers[attribute.messageId.peerId] {
let inlineBotNameColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
let nameString = NSAttributedString(string: EnginePeer(sourcePeer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder), font: inlineBotPrefixFont, textColor: inlineBotNameColor)
viaBotApply = viaBotLayout(TextNodeLayoutArguments(attributedString: nameString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: max(0, availableWidth), height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
}
}
}
}
var forwardSource: Peer?
var forwardAuthorSignature: String?
var forwardInfoSizeApply: (CGSize, (CGFloat) -> ChatMessageForwardInfoNode)?
if !ignoreForward, let forwardInfo = item.message.forwardInfo {
let forwardPsaType = forwardInfo.psaType
if let source = forwardInfo.source {
forwardSource = source
if let authorSignature = forwardInfo.authorSignature {
forwardAuthorSignature = authorSignature
} else if let forwardInfoAuthor = forwardInfo.author, forwardInfoAuthor.id != source.id {
forwardAuthorSignature = EnginePeer(forwardInfoAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
} else {
forwardAuthorSignature = nil
}
} else {
if let currentForwardInfo = currentForwardInfo, forwardInfo.author == nil && currentForwardInfo.0 != nil {
forwardSource = nil
forwardAuthorSignature = currentForwardInfo.0.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
} else {
forwardSource = forwardInfo.author
forwardAuthorSignature = forwardInfo.authorSignature
}
}
let availableWidth = max(60.0, availableContentWidth - 210.0 + 6.0)
forwardInfoSizeApply = makeForwardInfoLayout(item.presentationData, item.presentationData.strings, .standalone, forwardSource, forwardAuthorSignature, forwardPsaType, CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude))
}
var notConsumed = false var notConsumed = false
for attribute in item.message.attributes { for attribute in item.message.attributes {
if let attribute = attribute as? ConsumableContentMessageAttribute { if let attribute = attribute as? ConsumableContentMessageAttribute {
@ -412,10 +542,21 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
let effectiveAudioTranscriptionState = updatedAudioTranscriptionState ?? audioTranscriptionState let effectiveAudioTranscriptionState = updatedAudioTranscriptionState ?? audioTranscriptionState
if replyInfoApply != nil || viaBotApply != nil || forwardInfoSizeApply != nil {
if let currentReplyBackgroundNode = currentReplyBackgroundNode {
updatedReplyBackgroundNode = currentReplyBackgroundNode
} else {
updatedReplyBackgroundNode = NavigationBackgroundNode(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper))
}
updatedReplyBackgroundNode?.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate)
}
return (result, { [weak self] layoutData, animation in return (result, { [weak self] layoutData, animation in
if let strongSelf = self { if let strongSelf = self {
strongSelf.item = item strongSelf.item = item
strongSelf.videoFrame = displayVideoFrame strongSelf.videoFrame = displayVideoFrame
strongSelf.appliedForwardInfo = (forwardSource, forwardAuthorSignature)
strongSelf.secretProgressIcon = secretProgressIcon strongSelf.secretProgressIcon = secretProgressIcon
strongSelf.automaticDownload = automaticDownload strongSelf.automaticDownload = automaticDownload
@ -737,6 +878,112 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} else { } else {
strongSelf.dateAndStatusNode.pressed = nil strongSelf.dateAndStatusNode.pressed = nil
} }
if let updatedReplyBackgroundNode = updatedReplyBackgroundNode {
if strongSelf.replyBackgroundNode == nil {
strongSelf.replyBackgroundNode = updatedReplyBackgroundNode
strongSelf.addSubnode(updatedReplyBackgroundNode)
}
} else if let replyBackgroundNode = strongSelf.replyBackgroundNode {
replyBackgroundNode.removeFromSupernode()
strongSelf.replyBackgroundNode = nil
}
var messageInfoSize = CGSize()
if let (viaBotLayout, _) = viaBotApply, forwardInfoSizeApply == nil {
messageInfoSize = CGSize(width: viaBotLayout.size.width + 1.0, height: 0.0)
}
if let (forwardInfoSize, _) = forwardInfoSizeApply {
messageInfoSize = CGSize(width: max(messageInfoSize.width, forwardInfoSize.width + 2.0), height: 0.0)
}
if let (replyInfoSize, _) = replyInfoApply {
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: 0.0)
}
var width = width
if !scaleProgress.isZero {
width += avatarInset
}
if let (viaBotLayout, viaBotApply) = viaBotApply, forwardInfoSizeApply == nil {
let viaBotNode = viaBotApply()
if strongSelf.viaBotNode == nil {
strongSelf.viaBotNode = viaBotNode
strongSelf.addSubnode(viaBotNode)
}
let viaBotFrame = CGRect(origin: CGPoint(x: (!incoming ? 11.0 : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0), size: viaBotLayout.size)
animation.animator.updateFrame(layer: viaBotNode.layer, frame: viaBotFrame, completion: nil)
messageInfoSize = CGSize(width: messageInfoSize.width, height: viaBotLayout.size.height)
} else if let viaBotNode = strongSelf.viaBotNode {
viaBotNode.removeFromSupernode()
strongSelf.viaBotNode = nil
}
if let (forwardInfoSize, forwardInfoApply) = forwardInfoSizeApply {
let forwardInfoNode = forwardInfoApply(forwardInfoSize.width)
if strongSelf.forwardInfoNode == nil {
strongSelf.forwardInfoNode = forwardInfoNode
strongSelf.addSubnode(forwardInfoNode)
if animation.isAnimated {
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
}
let forwardInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? 12.0 : (width - messageInfoSize.width - bubbleEdgeInset - 8.0 + 10.0)), y: 8.0 + messageInfoSize.height), size: forwardInfoSize)
animation.animator.updateFrame(layer: forwardInfoNode.layer, frame: forwardInfoFrame, completion: nil)
messageInfoSize = CGSize(width: messageInfoSize.width, height: messageInfoSize.height + forwardInfoSize.height - 1.0)
} else if let forwardInfoNode = strongSelf.forwardInfoNode {
if animation.isAnimated {
if let forwardInfoNode = strongSelf.forwardInfoNode {
strongSelf.forwardInfoNode = nil
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak forwardInfoNode] _ in
forwardInfoNode?.removeFromSupernode()
})
}
} else {
forwardInfoNode.removeFromSupernode()
strongSelf.forwardInfoNode = nil
}
}
if let (replyInfoSize, replyInfoApply) = replyInfoApply {
let replyInfoNode = replyInfoApply(false)
if strongSelf.replyInfoNode == nil {
strongSelf.replyInfoNode = replyInfoNode
strongSelf.addSubnode(replyInfoNode)
}
let replyInfoFrame = CGRect(origin: CGPoint(x: (!incoming ? (bubbleEdgeInset + 11.0) : (width - messageInfoSize.width - bubbleEdgeInset - 9.0 + 10.0)), y: 8.0 + messageInfoSize.height), size: replyInfoSize)
animation.animator.updateFrame(layer: replyInfoNode.layer, frame: replyInfoFrame, completion: nil)
messageInfoSize = CGSize(width: max(messageInfoSize.width, replyInfoSize.width), height: messageInfoSize.height + replyInfoSize.height)
} else if let replyInfoNode = strongSelf.replyInfoNode {
replyInfoNode.removeFromSupernode()
strongSelf.replyInfoNode = nil
}
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
let replyBackgroundFrame = CGRect(origin: CGPoint(x: (!incoming ? (bubbleEdgeInset + 10.0) : (width - messageInfoSize.width - bubbleEdgeInset)) - 4.0, y: 6.0), size: CGSize(width: messageInfoSize.width + 8.0, height: messageInfoSize.height + 5.0))
animation.animator.updateFrame(layer: replyBackgroundNode.layer, frame: replyBackgroundFrame, completion: nil)
let cornerRadius = replyBackgroundNode.frame.height <= 22.0 ? replyBackgroundNode.frame.height / 2.0 : 8.0
replyBackgroundNode.update(size: replyBackgroundNode.bounds.size, cornerRadius: cornerRadius, transition: .immediate)
}
let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
if let viaBotNode = strongSelf.viaBotNode {
transition.updateAlpha(node: viaBotNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
}
if let replyBackgroundNode = strongSelf.replyBackgroundNode {
transition.updateAlpha(node: replyBackgroundNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
}
if let forwardInfoNode = strongSelf.forwardInfoNode {
transition.updateAlpha(node: forwardInfoNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
}
if let replyInfoNode = strongSelf.replyInfoNode {
transition.updateAlpha(node: replyInfoNode, alpha: strongSelf.isPlaying ? 0.0 : 1.0)
}
} }
}) })
} }
@ -962,6 +1209,39 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
switch gesture { switch gesture {
case .tap: case .tap:
if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) {
if let item = self.item {
for attribute in item.message.attributes {
if let attribute = attribute as? ReplyMessageAttribute {
item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId)
return
}
}
}
}
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(location) {
if let item = self.item, let forwardInfo = item.message.forwardInfo {
if let sourceMessageId = forwardInfo.sourceMessageId {
if !item.message.id.peerId.isReplies, let channel = forwardInfo.author as? TelegramChannel, channel.addressName == nil {
if case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
} else if case .member = channel.participationStatus {
} else {
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, forwardInfoNode, nil)
return
}
}
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
return
} else if let peer = forwardInfo.source ?? forwardInfo.author {
item.controllerInteraction.openPeer(EnginePeer(peer), peer is TelegramUser ? .info : .chat(textInputState: nil, subject: nil, peekData: nil), nil, false)
return
} else if let _ = forwardInfo.authorSignature {
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
return
}
}
}
if let audioTranscriptionButton = self.audioTranscriptionButton, !audioTranscriptionButton.isHidden, audioTranscriptionButton.frame.contains(location) { if let audioTranscriptionButton = self.audioTranscriptionButton, !audioTranscriptionButton.isHidden, audioTranscriptionButton.frame.contains(location) {
self.transcribe() self.transcribe()
return return
@ -1007,9 +1287,6 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.bounds.contains(point) {
return nil
}
if let audioTranscriptionButton = self.audioTranscriptionButton, !audioTranscriptionButton.isHidden, audioTranscriptionButton.frame.contains(point) { if let audioTranscriptionButton = self.audioTranscriptionButton, !audioTranscriptionButton.isHidden, audioTranscriptionButton.frame.contains(point) {
return audioTranscriptionButton return audioTranscriptionButton
} }
@ -1021,6 +1298,12 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
return playbackNode.view return playbackNode.view
} }
} }
if let forwardInfoNode = self.forwardInfoNode, forwardInfoNode.frame.contains(point), !forwardInfoNode.alpha.isZero {
return self.view
}
if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(point), !replyInfoNode.alpha.isZero {
return self.view
}
if let statusNode = self.statusNode, statusNode.supernode != nil, !statusNode.isHidden, statusNode.frame.contains(point) { if let statusNode = self.statusNode, statusNode.supernode != nil, !statusNode.isHidden, statusNode.frame.contains(point) {
return self.view return self.view
} }
@ -1028,6 +1311,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
if let videoNode = self.videoNode, videoNode.frame.contains(point) { if let videoNode = self.videoNode, videoNode.frame.contains(point) {
return self.view return self.view
} }
if !self.bounds.contains(point) {
return nil
}
return super.hitTest(point, with: event) return super.hitTest(point, with: event)
} }
@ -1072,16 +1358,16 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
return nil return nil
} }
static func asyncLayout(_ node: ChatMessageInteractiveInstantVideoNode?) -> (_ item: ChatMessageBubbleContentItem, _ width: CGFloat, _ displaySize: CGSize, _ maximumDisplaySize: CGSize, _ scaleProgress: CGFloat, _ statusType: ChatMessageInteractiveInstantVideoNodeStatusType, _ automaticDownload: Bool) -> (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> ChatMessageInteractiveInstantVideoNode) { static func asyncLayout(_ node: ChatMessageInteractiveInstantVideoNode?) -> (_ item: ChatMessageBubbleContentItem, _ width: CGFloat, _ displaySize: CGSize, _ maximumDisplaySize: CGSize, _ scaleProgress: CGFloat, _ statusType: ChatMessageInteractiveInstantVideoNodeStatusType, _ automaticDownload: Bool, _ avatarInset: CGFloat) -> (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> ChatMessageInteractiveInstantVideoNode) {
let makeLayout = node?.asyncLayout() let makeLayout = node?.asyncLayout()
return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload in return { item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload, avatarInset in
var createdNode: ChatMessageInteractiveInstantVideoNode? var createdNode: ChatMessageInteractiveInstantVideoNode?
let sizeAndApplyLayout: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> Void) let sizeAndApplyLayout: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ListViewItemUpdateAnimation) -> Void)
if let makeLayout = makeLayout { if let makeLayout = makeLayout {
sizeAndApplyLayout = makeLayout(item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload) sizeAndApplyLayout = makeLayout(item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload, avatarInset)
} else { } else {
let node = ChatMessageInteractiveInstantVideoNode() let node = ChatMessageInteractiveInstantVideoNode()
sizeAndApplyLayout = node.asyncLayout()(item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload) sizeAndApplyLayout = node.asyncLayout()(item, width, displaySize, maximumDisplaySize, scaleProgress, statusType, automaticDownload, avatarInset)
createdNode = node createdNode = node
} }
return (sizeAndApplyLayout.0, { [weak node] layoutData, transition in return (sizeAndApplyLayout.0, { [weak node] layoutData, transition in
@ -1275,7 +1561,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
let targetFrame = targetNode.view.convert(targetNode.bounds, to: self.view) let targetFrame = targetNode.view.convert(targetNode.bounds, to: self.view)
animator.animatePosition(layer: videoNode.layer, from: videoNode.position, to: targetFrame.center, completion: { _ in animator.animatePosition(layer: videoNode.layer, from: videoNode.position, to: targetFrame.center, completion: { _ in
self.isHidden = true self.isHidden = true
self.customIsHidden = true self.canAttachContent = true
}) })
let targetScale = targetNode.frame.width / videoNode.bounds.width let targetScale = targetNode.frame.width / videoNode.bounds.width
animator.animateScale(layer: videoNode.layer, from: self.imageScale, to: targetScale, completion: nil) animator.animateScale(layer: videoNode.layer, from: self.imageScale, to: targetScale, completion: nil)
@ -1297,8 +1583,21 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
targetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) targetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
let verticalDelta = (videoNode.position.y - targetFrame.center.y) * 2.0 let verticalDelta = (videoNode.position.y - targetFrame.center.y) * 2.0
animator.animatePosition(layer: node.textNode.layer, from: node.textNode.position.offsetBy(dx: 0.0, dy: verticalDelta), to: node.textNode.position, completion: nil) animator.animatePosition(layer: node.textClippingNode.layer, from: node.textClippingNode.position.offsetBy(dx: 0.0, dy: verticalDelta), to: node.textClippingNode.position, completion: nil)
node.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) node.textClippingNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
if let maskImage = generateGradientImage(size: CGSize(width: 8.0, height: 10.0), colors: [UIColor.black, UIColor.black, UIColor.clear], locations: [0.0, 0.1, 1.0], direction: .vertical) {
let textClippingFrame = node.textClippingNode.frame
let maskView = UIImageView(image: maskImage.stretchableImage(withLeftCapWidth: 0, topCapHeight: 1))
node.textClippingNode.view.mask = maskView
maskView.frame = CGRect(origin: CGPoint(), size: CGSize(width: textClippingFrame.width, height: maskImage.size.height))
animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(), size: textClippingFrame.size), completion: { [weak maskView, weak node] _ in
maskView?.removeFromSuperview()
node?.textClippingNode.view.mask = nil
})
}
} }
if let audioTranscriptionButton = self.audioTranscriptionButton, let targetAudioTranscriptionButton = node.audioTranscriptionButton { if let audioTranscriptionButton = self.audioTranscriptionButton, let targetAudioTranscriptionButton = node.audioTranscriptionButton {
@ -1335,6 +1634,19 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
node.fetchingTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration - 0.05, delay: 0.05) node.fetchingTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration - 0.05, delay: 0.05)
} }
if let viaBotNode = self.viaBotNode {
viaBotNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
}
if let replyBackgroundNode = self.replyBackgroundNode {
replyBackgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
}
if let forwardInfoNode = self.forwardInfoNode {
forwardInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
}
if let replyInfoNode = self.replyInfoNode {
replyInfoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
}
} }
func animateFrom(_ node: ChatMessageInteractiveFileNode, animator: ControlledTransitionAnimator) { func animateFrom(_ node: ChatMessageInteractiveFileNode, animator: ControlledTransitionAnimator) {
@ -1374,8 +1686,21 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
sourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration) sourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
let verticalDelta = (videoNode.position.y - sourceFrame.center.y) * 2.0 let verticalDelta = (videoNode.position.y - sourceFrame.center.y) * 2.0
animator.animatePosition(layer: node.textNode.layer, from: node.textNode.position, to: node.textNode.position.offsetBy(dx: 0.0, dy: verticalDelta), completion: nil) animator.animatePosition(layer: node.textClippingNode.layer, from: node.textClippingNode.position, to: node.textClippingNode.position.offsetBy(dx: 0.0, dy: verticalDelta), completion: nil)
node.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration) node.textClippingNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
if let maskImage = generateGradientImage(size: CGSize(width: 8.0, height: 10.0), colors: [UIColor.black, UIColor.black, UIColor.clear], locations: [0.0, 0.1, 1.0], direction: .vertical) {
let textClippingFrame = node.textClippingNode.frame
let maskView = UIImageView(image: maskImage.stretchableImage(withLeftCapWidth: 0, topCapHeight: 1))
node.textClippingNode.view.mask = maskView
maskView.frame = CGRect(origin: CGPoint(), size: textClippingFrame.size)
animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(), size: CGSize(width: textClippingFrame.width, height: maskImage.size.height)), completion: { [weak maskView, weak node] _ in
maskView?.removeFromSuperview()
node?.textClippingNode.view.mask = nil
})
}
} }
if let audioTranscriptionButton = self.audioTranscriptionButton, let sourceAudioTranscriptionButton = node.audioTranscriptionButton { if let audioTranscriptionButton = self.audioTranscriptionButton, let sourceAudioTranscriptionButton = node.audioTranscriptionButton {
@ -1413,6 +1738,19 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
node.fetchingTextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration) node.fetchingTextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
} }
self.customIsHidden = false if let viaBotNode = self.viaBotNode {
viaBotNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
if let replyBackgroundNode = self.replyBackgroundNode {
replyBackgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
if let forwardInfoNode = self.forwardInfoNode {
forwardInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
if let replyInfoNode = self.replyInfoNode {
replyInfoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
self.canAttachContent = false
} }
} }

View File

@ -34,10 +34,10 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var invoice: TelegramMediaInvoice? var invoice: TelegramMediaInvoice?
for media in item.message.media { for media in item.message.media {
if let media = media as? TelegramMediaInvoice { if let media = media as? TelegramMediaInvoice {

View File

@ -87,7 +87,7 @@ private func mediaMergeableStyle(_ media: Media) -> ChatMessageMerge {
return .semanticallyMerged return .semanticallyMerged
case let .Video(_, _, flags): case let .Video(_, _, flags):
if flags.contains(.instantRoundVideo) { if flags.contains(.instantRoundVideo) {
return .semanticallyMerged return .none
} }
default: default:
break break

View File

@ -64,7 +64,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
self.view.addGestureRecognizer(tapRecognizer) self.view.addGestureRecognizer(tapRecognizer)
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeImageLayout = self.imageNode.asyncLayout() let makeImageLayout = self.imageNode.asyncLayout()
let makePinLayout = self.pinNode.asyncLayout() let makePinLayout = self.pinNode.asyncLayout()
let statusLayout = self.dateAndStatusNode.asyncLayout() let statusLayout = self.dateAndStatusNode.asyncLayout()
@ -73,7 +73,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
let previousMedia = self.media let previousMedia = self.media
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var selectedMedia: TelegramMediaMap? var selectedMedia: TelegramMediaMap?
var activeLiveBroadcastingTimeout: Int32? var activeLiveBroadcastingTimeout: Int32?
for media in item.message.media { for media in item.message.media {

View File

@ -71,10 +71,10 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let interactiveImageLayout = self.interactiveImageNode.asyncLayout() let interactiveImageLayout = self.interactiveImageNode.asyncLayout()
return { item, layoutConstants, preparePosition, selection, constrainedSize in return { item, layoutConstants, preparePosition, selection, constrainedSize, _ in
var selectedMedia: Media? var selectedMedia: Media?
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
var automaticPlayback: Bool = false var automaticPlayback: Bool = false

View File

@ -1005,7 +1005,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
} }
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeTextLayout = TextNode.asyncLayout(self.textNode) let makeTextLayout = TextNode.asyncLayout(self.textNode)
let makeTypeLayout = TextNode.asyncLayout(self.typeNode) let makeTypeLayout = TextNode.asyncLayout(self.typeNode)
let makeVotersLayout = TextNode.asyncLayout(self.votersNode) let makeVotersLayout = TextNode.asyncLayout(self.votersNode)
@ -1030,7 +1030,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
} }
} }
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in

View File

@ -511,10 +511,10 @@ final class ChatMessageReactionsFooterContentNode: ChatMessageBubbleContentNode
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let buttonsNode = self.buttonsNode let buttonsNode = self.buttonsNode
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
//let displaySeparator: Bool //let displaySeparator: Bool

View File

@ -29,11 +29,11 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let textLayout = TextNode.asyncLayout(self.textNode) let textLayout = TextNode.asyncLayout(self.textNode)
let statusLayout = self.statusNode.asyncLayout() let statusLayout = self.statusNode.asyncLayout()
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in

View File

@ -120,14 +120,14 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let textLayout = TextNodeWithEntities.asyncLayout(self.textNode) let textLayout = TextNodeWithEntities.asyncLayout(self.textNode)
let spoilerTextLayout = TextNodeWithEntities.asyncLayout(self.spoilerTextNode) let spoilerTextLayout = TextNodeWithEntities.asyncLayout(self.spoilerTextNode)
let statusLayout = self.statusNode.asyncLayout() let statusLayout = self.statusNode.asyncLayout()
let currentCachedChatMessageText = self.cachedChatMessageText let currentCachedChatMessageText = self.cachedChatMessageText
return { item, layoutConstants, _, _, _ in return { item, layoutConstants, _, _, _, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in

View File

@ -27,10 +27,10 @@ final class ChatMessageUnsupportedBubbleContentNode: ChatMessageBubbleContentNod
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let makeButtonLayout = ChatMessageAttachedContentButtonNode.asyncLayout(self.buttonNode) let makeButtonLayout = ChatMessageAttachedContentButtonNode.asyncLayout(self.buttonNode)
return { item, layoutConstants, _, _, constrainedSize in return { item, layoutConstants, _, _, constrainedSize, _ in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in

View File

@ -112,10 +112,10 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
let contentNodeLayout = self.contentNode.asyncLayout() let contentNodeLayout = self.contentNode.asyncLayout()
return { item, layoutConstants, preparePosition, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize, _ in
var webPage: TelegramMediaWebpage? var webPage: TelegramMediaWebpage?
var webPageContent: TelegramMediaWebpageLoadedContent? var webPageContent: TelegramMediaWebpageLoadedContent?
for media in item.message.media { for media in item.message.media {