import Foundation import UIKit import Display import AsyncDisplayKit import TelegramCore import SyncCore import SwiftSignalKit import Postbox import TelegramPresentationData import AvatarNode import AccountContext final class ChatMediaInputPeerSpecificItem: ListViewItem { let context: AccountContext let inputNodeInteraction: ChatMediaInputNodeInteraction let collectionId: ItemCollectionId let peer: Peer let selectedItem: () -> Void let theme: PresentationTheme var selectable: Bool { return true } init(context: AccountContext, inputNodeInteraction: ChatMediaInputNodeInteraction, collectionId: ItemCollectionId, peer: Peer, theme: PresentationTheme, selected: @escaping () -> Void) { self.context = context self.inputNodeInteraction = inputNodeInteraction self.collectionId = collectionId self.peer = peer self.selectedItem = selected self.theme = theme } func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { async { let node = ChatMediaInputPeerSpecificItemNode() node.contentSize = boundingSize node.insets = ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem) node.inputNodeInteraction = self.inputNodeInteraction Queue.mainQueue().async { completion(node, { return (nil, { _ in node.updateItem(context: self.context, peer: self.peer, collectionId: self.collectionId, theme: self.theme) node.updateAppearanceTransition(transition: .immediate) }) }) } } } public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { Queue.mainQueue().async { completion(ListViewItemNodeLayout(contentSize: node().contentSize, insets: ChatMediaInputNode.setupPanelIconInsets(item: self, previousItem: previousItem, nextItem: nextItem)), { _ in (node() as? ChatMediaInputPeerSpecificItemNode)?.updateItem(context: self.context, peer: self.peer, collectionId: self.collectionId, theme: self.theme) }) } } func selected(listView: ListView) { self.selectedItem() } } private let avatarFont = avatarPlaceholderFont(size: 12.0) private let boundingSize = CGSize(width: 41.0, height: 41.0) private let boundingImageSize = CGSize(width: 28.0, height: 28.0) private let highlightSize = CGSize(width: 35.0, height: 35.0) private let verticalOffset: CGFloat = 3.0 final class ChatMediaInputPeerSpecificItemNode: ListViewItemNode { private let avatarNode: AvatarNode private let highlightNode: ASImageNode var inputNodeInteraction: ChatMediaInputNodeInteraction? var currentCollectionId: ItemCollectionId? private var theme: PresentationTheme? private let stickerFetchedDisposable = MetaDisposable() init() { self.highlightNode = ASImageNode() self.highlightNode.isLayerBacked = true self.highlightNode.isHidden = true self.avatarNode = AvatarNode(font: avatarFont) self.avatarNode.isLayerBacked = !smartInvertColorsEnabled() self.avatarNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) let imageSize = CGSize(width: 26.0, height: 26.0) self.avatarNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - imageSize.height) / 2.0)), size: imageSize) self.highlightNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - highlightSize.width) / 2.0) + verticalOffset, y: floor((boundingSize.height - highlightSize.height) / 2.0)), size: highlightSize) super.init(layerBacked: false, dynamicBounce: false) self.addSubnode(self.highlightNode) self.addSubnode(self.avatarNode) } deinit { self.stickerFetchedDisposable.dispose() } func updateItem(context: AccountContext, peer: Peer, collectionId: ItemCollectionId, theme: PresentationTheme) { self.currentCollectionId = collectionId if self.theme !== theme { self.theme = theme self.highlightNode.image = PresentationResourcesChat.chatMediaInputPanelHighlightedIconImage(theme) } self.avatarNode.setPeer(context: context, theme: theme, peer: peer) } func updateIsHighlighted() { assert(Queue.mainQueue().isCurrent()) if let currentCollectionId = self.currentCollectionId, let inputNodeInteraction = self.inputNodeInteraction { self.highlightNode.isHidden = inputNodeInteraction.highlightedItemCollectionId != currentCollectionId } } func updateAppearanceTransition(transition: ContainedViewLayoutTransition) { assert(Queue.mainQueue().isCurrent()) if let inputNodeInteraction = self.inputNodeInteraction { transition.updateSublayerTransformScale(node: self, scale: inputNodeInteraction.appearanceTransition) } } override func animateAdded(_ currentTimestamp: Double, duration: Double) { self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } override func animateRemoved(_ currentTimestamp: Double, duration: Double) { self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) } }