import Foundation import UIKit import AsyncDisplayKit import TelegramPresentationData import ChatPresentationInterfaceState import AccountContext import ChatSendMessageActionUI import SwiftSignalKit import ComponentFlow import Display import Postbox import TelegramCore import WallpaperBackgroundNode import AudioWaveform import ChatMessageItemView public final class ChatSendAudioMessageContextPreview: UIView, ChatSendMessageContextScreenMediaPreview { private let context: AccountContext private let presentationData: PresentationData private let wallpaperBackgroundNode: WallpaperBackgroundNode? private let waveform: AudioWaveform private var messageNodes: [ListViewItemNode]? private let messagesContainer: UIView public var isReady: Signal { return .single(true) } public var view: UIView { return self } public var globalClippingRect: CGRect? { return nil } public var layoutType: ChatSendMessageContextScreenMediaPreviewLayoutType { return .message } public init(context: AccountContext, presentationData: PresentationData, wallpaperBackgroundNode: WallpaperBackgroundNode?, waveform: AudioWaveform) { self.context = context self.presentationData = presentationData self.wallpaperBackgroundNode = wallpaperBackgroundNode self.waveform = waveform self.messagesContainer = UIView() self.messagesContainer.layer.sublayerTransform = CATransform3DMakeScale(-1.0, -1.0, 1.0) super.init(frame: CGRect()) self.addSubview(self.messagesContainer) } required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { } public func animateIn(transition: Transition) { transition.animateAlpha(view: self.messagesContainer, from: 0.0, to: 1.0) transition.animateScale(view: self.messagesContainer, from: 0.001, to: 1.0) } public func animateOut(transition: Transition) { transition.setAlpha(view: self.messagesContainer, alpha: 0.0) transition.setScale(view: self.messagesContainer, scale: 0.001) } public func animateOutOnSend(transition: Transition) { transition.setAlpha(view: self.messagesContainer, alpha: 0.0) } public func update(containerSize: CGSize, transition: Transition) -> CGSize { let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: self.waveform.makeBitstream())] let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: self.context.account.peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [voiceMedia], peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let item = self.context.sharedContext.makeChatMessagePreviewItem( context: self.context, messages: [message], theme: presentationData.theme, strings: presentationData.strings, wallpaper: presentationData.chatWallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: presentationData.chatBubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .fetchStatus(.Local), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false, isPreview: true, isStandalone: true ) let items = [item] let params = ListViewItemLayoutParams(width: containerSize.width, leftInset: 0.0, rightInset: 0.0, availableHeight: containerSize.height) if let messageNodes = self.messageNodes { for i in 0 ..< items.count { let itemNode = messageNodes[i] items[i].updateNode(async: { $0() }, node: { return itemNode }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: containerSize.width, height: layout.size.height)) itemNode.contentSize = layout.contentSize itemNode.insets = layout.insets itemNode.frame = nodeFrame itemNode.isUserInteractionEnabled = false apply(ListViewItemApply(isOnScreen: true)) }) } } else { var messageNodes: [ListViewItemNode] = [] for i in 0 ..< items.count { var itemNode: ListViewItemNode? items[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], completion: { node, apply in itemNode = node apply().1(ListViewItemApply(isOnScreen: true)) }) itemNode!.isUserInteractionEnabled = false messageNodes.append(itemNode!) self.messagesContainer.addSubview(itemNode!.view) } self.messageNodes = messageNodes } guard let messageNode = self.messageNodes?.first as? ChatMessageItemView else { return CGSize(width: 10.0, height: 10.0) } let contentFrame = messageNode.contentFrame() self.messagesContainer.frame = CGRect(origin: CGPoint(x: 6.0, y: 3.0), size: CGSize(width: contentFrame.width, height: contentFrame.height)) return CGSize(width: contentFrame.width - 4.0, height: contentFrame.height + 2.0) } }