Swiftgram/submodules/TelegramUI/Sources/MediaInputPaneTrendingItem.swift
2020-12-10 19:16:02 +04:00

194 lines
8.2 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import SyncCore
import TelegramPresentationData
import StickerResources
import AccountContext
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ShimmerEffect
private let titleFont = Font.bold(16.0)
private let statusFont = Font.regular(15.0)
private let buttonFont = Font.medium(13.0)
final class TrendingTopItemNode: ASDisplayNode {
private let imageNode: TransformImageNode
private var animationNode: AnimatedStickerNode?
private var placeholderNode: StickerShimmerEffectNode?
public private(set) var file: TelegramMediaFile? = nil
public private(set) var theme: PresentationTheme?
private var listAppearance = false
private var itemSize: CGSize?
private let loadDisposable = MetaDisposable()
var currentIsPreviewing = false
var visibility: Bool = false {
didSet {
if oldValue != self.visibility {
self.animationNode?.visibility = self.visibility
}
}
}
override init() {
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = [.subsequentUpdates]
self.placeholderNode = StickerShimmerEffectNode()
self.placeholderNode?.isUserInteractionEnabled = false
super.init()
self.addSubnode(self.imageNode)
if let placeholderNode = self.placeholderNode {
self.addSubnode(placeholderNode)
}
var firstTime = true
self.imageNode.imageUpdated = { [weak self] image in
guard let strongSelf = self else {
return
}
if image != nil {
strongSelf.removePlaceholder(animated: !firstTime)
}
firstTime = false
}
}
deinit {
self.loadDisposable.dispose()
}
private func removePlaceholder(animated: Bool) {
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
if !animated {
placeholderNode.removeFromSupernode()
} else {
placeholderNode.allowsGroupOpacity = true
placeholderNode.alpha = 0.0
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderNode] _ in
placeholderNode?.removeFromSupernode()
placeholderNode?.allowsGroupOpacity = false
})
}
}
}
private var absoluteLocation: (CGRect, CGSize)?
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
self.absoluteLocation = (rect, containerSize)
if let placeholderNode = placeholderNode {
placeholderNode.updateAbsoluteRect(rect, within: containerSize)
}
}
func update(theme: PresentationTheme, listAppearance: Bool) {
self.theme = theme
self.listAppearance = listAppearance
let backgroundColor: UIColor
let foregroundColor: UIColor
let shimmeringColor: UIColor
if listAppearance {
backgroundColor = theme.list.plainBackgroundColor
foregroundColor = theme.list.itemPlainSeparatorColor.blitOver(backgroundColor, alpha: 0.3)
shimmeringColor = theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4)
} else {
backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0)
foregroundColor = theme.chat.inputMediaPanel.stickersSectionTextColor.blitOver(backgroundColor, alpha: 0.15)
shimmeringColor = theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.3)
}
if let placeholderNode = self.placeholderNode, let file = self.file {
placeholderNode.update(backgroundColor: backgroundColor, foregroundColor: foregroundColor, shimmeringColor: shimmeringColor, data: file.immediateThumbnailData, size: placeholderNode.frame.size)
}
}
func setup(account: Account, item: StickerPackItem, itemSize: CGSize, synchronousLoads: Bool) {
self.file = item.file
self.itemSize = itemSize
if item.file.isAnimatedSticker {
let animationNode: AnimatedStickerNode
if let currentAnimationNode = self.animationNode {
animationNode = currentAnimationNode
} else {
animationNode = AnimatedStickerNode()
animationNode.transform = self.imageNode.transform
animationNode.visibility = self.visibility
self.animationNode = animationNode
if let placeholderNode = self.placeholderNode {
self.insertSubnode(animationNode, belowSubnode: placeholderNode)
} else {
self.addSubnode(animationNode)
}
}
let dimensions = item.file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: item.file, small: false, size: fittedDimensions, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads)
animationNode.started = { [weak self] in
self?.imageNode.alpha = 0.0
}
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: item.file.resource).start())
} else {
self.imageNode.setSignal(chatMessageSticker(account: account, file: item.file, small: true, synchronousLoad: synchronousLoads), attemptSynchronously: synchronousLoads)
if let currentAnimationNode = self.animationNode {
self.animationNode = nil
currentAnimationNode.removeFromSupernode()
}
self.loadDisposable.set(freeMediaFileResourceInteractiveFetched(account: account, fileReference: stickerPackFileReference(item.file), resource: chatMessageStickerResource(file: item.file, small: true)).start())
}
}
func updatePreviewing(animated: Bool, isPreviewing: Bool) {
if self.currentIsPreviewing != isPreviewing {
self.currentIsPreviewing = isPreviewing
if isPreviewing {
if animated {
self.layer.animateSpring(from: 1.0 as NSNumber, to: 0.8 as NSNumber, keyPath: "transform.scale", duration: 0.4, removeOnCompletion: false)
}
} else {
self.layer.removeAnimation(forKey: "transform.scale")
if animated {
self.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
}
}
}
}
override func layout() {
super.layout()
if let dimensions = self.file?.dimensions, let itemSize = self.itemSize {
let imageSize = dimensions.cgSize.aspectFitted(itemSize)
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
}
self.imageNode.frame = self.bounds
self.animationNode?.updateLayout(size: self.bounds.size)
let size = self.bounds.size
let boundingSize = size
if let placeholderNode = self.placeholderNode {
let placeholderFrame = CGRect(origin: CGPoint(x: floor((size.width - boundingSize.width) / 2.0), y: floor((size.height - boundingSize.height) / 2.0)), size: boundingSize)
placeholderNode.frame = placeholderFrame
if let theme = self.theme {
self.update(theme: theme, listAppearance: self.listAppearance)
}
}
}
}