import UIKit import Display import SyncCore import TelegramCore import AccountContext import SwiftSignalKit import AnimatedStickerNode import TelegramAnimatedStickerNode import StickerResources import LegacyComponents class LegacyPaintStickerView: UIView, TGPhotoPaintStickerRenderView { var started: ((Double) -> Void)? private let context: AccountContext private let file: TelegramMediaFile private var currentSize: CGSize? private var dimensions: CGSize? private let imageNode: TransformImageNode private var animationNode: AnimatedStickerNode? private var didSetUpAnimationNode = false private let stickerFetchedDisposable = MetaDisposable() private let cachedDisposable = MetaDisposable() init(context: AccountContext, file: TelegramMediaFile) { self.context = context self.file = file self.imageNode = TransformImageNode() super.init(frame: CGRect()) self.addSubnode(self.imageNode) self.setup() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { self.stickerFetchedDisposable.dispose() self.cachedDisposable.dispose() } func image() -> UIImage! { if self.imageNode.contents != nil { return UIImage(cgImage: self.imageNode.contents as! CGImage) } else { return nil } } func documentId() -> Int64 { return self.file.fileId.id } private func setup() { if let dimensions = self.file.dimensions { if self.file.isAnimatedSticker { if self.animationNode == nil { let animationNode = AnimatedStickerNode() self.animationNode = animationNode animationNode.started = { [weak self, weak animationNode] in self?.imageNode.isHidden = true if let animationNode = animationNode { let _ = (animationNode.status |> take(1) |> deliverOnMainQueue).start(next: { [weak self] status in self?.started?(status.duration) }) } } self.addSubnode(animationNode) } let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512) self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, file: self.file, small: false, size: dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0)))) self.updateVisibility() self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: self.file.resource).start()) } else { if let animationNode = self.animationNode { animationNode.visibility = false self.animationNode = nil animationNode.removeFromSupernode() self.imageNode.isHidden = false self.didSetUpAnimationNode = false } self.imageNode.setSignal(chatMessageSticker(account: self.context.account, file: self.file, small: false, synchronousLoad: false)) self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, fileReference: stickerPackFileReference(self.file), resource: chatMessageStickerResource(file: self.file, small: false)).start()) } self.dimensions = dimensions.cgSize self.setNeedsLayout() } } var isVisible: Bool = true func setIsVisible(_ visible: Bool) { self.isVisible = visible self.updateVisibility() } var isPlaying = false func updateVisibility() { let isPlaying = self.isVisible if self.isPlaying != isPlaying { self.isPlaying = isPlaying self.animationNode?.visibility = isPlaying if isPlaying && !self.didSetUpAnimationNode { self.didSetUpAnimationNode = true let dimensions = self.file.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) let source = AnimatedStickerResourceSource(account: self.context.account, resource: self.file.resource) self.animationNode?.setup(source: source, width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct) self.cachedDisposable.set((source.cachedDataPath(width: 384, height: 384) |> deliverOn(Queue.concurrentDefaultQueue())).start()) } } } func seek(to timestamp: Double) { self.isVisible = false self.isPlaying = false self.animationNode?.seekTo(.timestamp(timestamp)) } func play() { self.isVisible = true self.isPlaying = true self.animationNode?.play() } func pause() { self.isVisible = false self.isPlaying = false self.animationNode?.pause() } func resetToStart() { self.isVisible = false self.isPlaying = false self.animationNode?.seekTo(.timestamp(0.0)) } override func layoutSubviews() { super.layoutSubviews() let size = self.bounds.size if size.width > 0 && self.currentSize != size { self.currentSize = size let sideSize: CGFloat = size.width let boundingSize = CGSize(width: sideSize, height: sideSize) if let dimensions = self.dimensions { let imageSize = dimensions.aspectFitted(boundingSize) self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))() self.imageNode.frame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (size.height - imageSize.height) / 2.0), size: imageSize) if let animationNode = self.animationNode { animationNode.frame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: (size.height - imageSize.height) / 2.0), size: imageSize) animationNode.updateLayout(size: imageSize) } } } } }