import Foundation import UIKit import Postbox import AsyncDisplayKit import Display import SwiftSignalKit import TelegramCore import AccountContext import ChatHistoryEntry import ChatControllerInteraction import TelegramPresentationData import ChatMessageItemCommon public enum ChatMessageItemContent: Sequence { case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, attributes: ChatMessageEntryAttributes, location: MessageHistoryEntryLocation?) case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)]) public func effectivelyIncoming(_ accountPeerId: PeerId, associatedData: ChatMessageItemAssociatedData? = nil) -> Bool { if let subject = associatedData?.subject, case let .messageOptions(_, _, info) = subject { if case .forward = info { return false } else if case let .link(link) = info { return link.isCentered } } switch self { case let .message(message, _, _, _, _): return message.effectivelyIncoming(accountPeerId) case let .group(messages): return messages[0].0.effectivelyIncoming(accountPeerId) } } public var index: MessageIndex { switch self { case let .message(message, _, _, _, _): return message.index case let .group(messages): return messages[0].0.index } } public var firstMessage: Message { switch self { case let .message(message, _, _, _, _): return message case let .group(messages): return messages[0].0 } } public var firstMessageAttributes: ChatMessageEntryAttributes { switch self { case let .message(_, _, _, attributes, _): return attributes case let .group(messages): return messages[0].3 } } public func makeIterator() -> AnyIterator<(Message, ChatMessageEntryAttributes)> { var index = 0 return AnyIterator { () -> (Message, ChatMessageEntryAttributes)? in switch self { case let .message(message, _, _, attributes, _): if index == 0 { index += 1 return (message, attributes) } else { index += 1 return nil } case let .group(messages): if index < messages.count { let currentIndex = index index += 1 return (messages[currentIndex].0, messages[currentIndex].3) } else { return nil } } } } } public enum ChatMessageItemAdditionalContent { case eventLogPreviousMessage(Message) case eventLogPreviousDescription(Message) case eventLogPreviousLink(Message) case eventLogGroupedMessages([Message], Bool) } public enum ChatMessageMerge: Int32 { case none = 0 case fullyMerged = 1 case semanticallyMerged = 2 public var merged: Bool { if case .none = self { return false } else { return true } } } public protocol ChatMessageAvatarHeaderNode: ListViewItemHeaderNode { func updateSelectionState(animated: Bool) } public protocol ChatMessageItem: ListViewItem { var presentationData: ChatPresentationData { get } var context: AccountContext { get } var chatLocation: ChatLocation { get } var associatedData: ChatMessageItemAssociatedData { get } var controllerInteraction: ChatControllerInteraction { get } var content: ChatMessageItemContent { get } var disableDate: Bool { get } var effectiveAuthorId: PeerId? { get } var additionalContent: ChatMessageItemAdditionalContent? { get } var headers: [ListViewItemHeader] { get } var message: Message { get } var read: Bool { get } var unsent: Bool { get } var sending: Bool { get } var failed: Bool { get } func mergedWithItems(top: ListViewItem?, bottom: ListViewItem?, isRotated: Bool) -> (top: ChatMessageMerge, bottom: ChatMessageMerge, dateAtBottom: Bool) } public func hasCommentButton(item: ChatMessageItem) -> Bool { let firstMessage = item.content.firstMessage var hasDiscussion = false if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) { hasDiscussion = true } if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.effectiveTopId == firstMessage.id { hasDiscussion = false } if firstMessage.adAttribute != nil { hasDiscussion = false } if hasDiscussion { var canComment = false if case .pinnedMessages = item.associatedData.subject { canComment = false } else if firstMessage.id.namespace == Namespaces.Message.Local { canComment = true } else { for attribute in firstMessage.attributes { if let attribute = attribute as? ReplyThreadMessageAttribute, let commentsPeerId = attribute.commentsPeerId { switch item.associatedData.channelDiscussionGroup { case .unknown: canComment = true case let .known(groupId): canComment = groupId == commentsPeerId } break } } } if canComment { return true } } else if firstMessage.id.peerId.isReplies { return true } return false }