Swiftgram/submodules/ImportStickerPackUI/Sources/StickerPackPreviewGridItem.swift
2021-06-18 04:21:15 +03:00

190 lines
7.1 KiB
Swift

import Foundation
import UIKit
import Display
import TelegramCore
import SyncCore
import SwiftSignalKit
import AsyncDisplayKit
import Postbox
import StickerResources
import AccountContext
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import TelegramPresentationData
import ShimmerEffect
final class StickerPackPreviewInteraction {
var previewedItem: ImportStickerPack.Sticker?
var playAnimatedStickers: Bool
init(playAnimatedStickers: Bool) {
self.playAnimatedStickers = playAnimatedStickers
}
}
final class StickerPackPreviewGridItem: GridItem {
let account: Account
let stickerItem: ImportStickerPack.Sticker
let interaction: StickerPackPreviewInteraction
let theme: PresentationTheme
let isEmpty: Bool
let section: GridSection? = nil
init(account: Account, stickerItem: ImportStickerPack.Sticker, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
self.account = account
self.stickerItem = stickerItem
self.interaction = interaction
self.theme = theme
self.isEmpty = isEmpty
}
func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode {
let node = StickerPackPreviewGridItemNode()
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
return node
}
func update(node: GridItemNode) {
guard let node = node as? StickerPackPreviewGridItemNode else {
assertionFailure()
return
}
node.setup(account: self.account, stickerItem: self.stickerItem, interaction: self.interaction, theme: self.theme, isEmpty: self.isEmpty)
}
}
private let textFont = Font.regular(20.0)
final class StickerPackPreviewGridItemNode: GridItemNode {
private var currentState: (Account, ImportStickerPack.Sticker?, CGSize)?
private var isEmpty: Bool?
private let imageNode: ASImageNode
private var animationNode: AnimatedStickerNode?
private var theme: PresentationTheme?
override var isVisibleInGrid: Bool {
didSet {
self.animationNode?.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
}
}
private var currentIsPreviewing = false
private let stickerFetchedDisposable = MetaDisposable()
var interaction: StickerPackPreviewInteraction?
var selected: (() -> Void)?
var stickerPackItem: ImportStickerPack.Sticker? {
return self.currentState?.1
}
override init() {
self.imageNode = ASImageNode()
super.init()
self.addSubnode(self.imageNode)
}
deinit {
self.stickerFetchedDisposable.dispose()
}
override func didLoad() {
super.didLoad()
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
}
func setup(account: Account, stickerItem: ImportStickerPack.Sticker?, interaction: StickerPackPreviewInteraction, theme: PresentationTheme, isEmpty: Bool) {
self.interaction = interaction
self.theme = theme
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 !== stickerItem || self.isEmpty != isEmpty {
var dimensions = CGSize(width: 512.0, height: 512.0)
if let stickerItem = stickerItem {
switch stickerItem.content {
case let .image(data):
if let animationNode = self.animationNode {
animationNode.visibility = false
self.animationNode = nil
animationNode.removeFromSupernode()
}
self.imageNode.isHidden = false
if let image = UIImage(data: data) {
self.imageNode.image = image
dimensions = image.size
}
case .animation:
self.imageNode.isHidden = true
let animationNode = AnimatedStickerNode()
self.animationNode = animationNode
self.addSubnode(animationNode)
let fittedDimensions = dimensions.aspectFitted(CGSize(width: 160.0, height: 160.0))
if let resource = stickerItem.resource {
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
}
animationNode.visibility = self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true
}
} else {
dimensions = CGSize()
}
self.currentState = (account, stickerItem, dimensions)
self.setNeedsLayout()
}
self.isEmpty = isEmpty
}
override func layout() {
super.layout()
let bounds = self.bounds
let boundsSide = min(bounds.size.width - 14.0, bounds.size.height - 14.0)
let boundingSize = CGSize(width: boundsSide, height: boundsSide)
if let (_, _, dimensions) = self.currentState {
let imageSize = dimensions.aspectFitted(boundingSize)
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
if let animationNode = self.animationNode {
animationNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
animationNode.updateLayout(size: imageSize)
}
}
}
func transitionNode() -> ASDisplayNode? {
return self
}
@objc func imageNodeTap(_ recognizer: UITapGestureRecognizer) {
}
func updatePreviewing(animated: Bool) {
var isPreviewing = false
if let (_, maybeItem, _) = self.currentState, let interaction = self.interaction, let item = maybeItem {
isPreviewing = interaction.previewedItem === item
}
if self.currentIsPreviewing != isPreviewing {
self.currentIsPreviewing = isPreviewing
if isPreviewing {
self.layer.sublayerTransform = CATransform3DMakeScale(0.8, 0.8, 1.0)
if animated {
self.layer.animateSpring(from: 1.0 as NSNumber, to: 0.8 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.4)
}
} else {
self.layer.sublayerTransform = CATransform3DIdentity
if animated {
self.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "sublayerTransform.scale", duration: 0.5)
}
}
}
}
}