Swiftgram/submodules/StickerPackPreviewUI/Sources/StickerPreviewControllerNode.swift
2019-11-03 00:44:55 +04:00

153 lines
6.6 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import SyncCore
import TelegramPresentationData
import AccountContext
import StickerResources
final class StickerPreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
private let context: AccountContext
private let presentationData: PresentationData
private let dimNode: ASDisplayNode
private var textNode: ASTextNode
private var imageNode: TransformImageNode
private var containerLayout: (ContainerViewLayout, CGFloat)?
private var item: StickerPackItem?
var dismiss: (() -> Void)?
var cancel: (() -> Void)?
init(context: AccountContext) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = presentationData.theme.list.plainBackgroundColor.withAlphaComponent(0.6)
self.textNode = ASTextNode()
self.imageNode = TransformImageNode()
self.imageNode.addSubnode(self.textNode)
super.init()
self.setViewBlock({
return UITracingLayerView()
})
self.addSubnode(self.dimNode)
self.addSubnode(self.imageNode)
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
self.containerLayout = (layout, navigationBarHeight)
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let boundingSize = CGSize(width: 180.0, height: 180.0)
if let item = self.item, let dimensitons = item.file.dimensions {
let textSpacing: CGFloat = 10.0
let textSize = self.textNode.measure(CGSize(width: 100.0, height: 100.0))
let imageSize = dimensitons.cgSize.aspectFitted(boundingSize)
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
let imageFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: (layout.size.height - imageSize.height - textSpacing - textSize.height) / 4.0), size: imageSize)
self.imageNode.frame = imageFrame
self.textNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - textSize.width) / 2.0), y: -textSize.height - textSpacing), size: textSize)
}
}
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.cancel?()
}
}
func animateIn(sourceNode: ASDisplayNode?) {
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
if let sourceNode = sourceNode {
let location = sourceNode.view.convert(CGPoint(x: sourceNode.bounds.midX, y: sourceNode.bounds.midY), to: self.view)
self.imageNode.layer.animateSpring(from: NSValue(cgPoint: location), to: NSValue(cgPoint: self.imageNode.layer.position), keyPath: "position", duration: 0.6, damping: 100.0)
self.imageNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, damping: 100.0)
}
self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
func animateOut(targetNode: ASDisplayNode?, completion: (() -> Void)? = nil) {
var dimCompleted = false
var itemCompleted = false
let internalCompletion: () -> Void = { [weak self] in
if let strongSelf = self, dimCompleted && itemCompleted {
strongSelf.dismiss?()
}
completion?()
}
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
dimCompleted = true
internalCompletion()
})
if let targetNode = targetNode {
let location = targetNode.view.convert(CGPoint(x: targetNode.bounds.midX, y: targetNode.bounds.midY), to: self.view)
self.imageNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2, removeOnCompletion: false)
self.imageNode.layer.animatePosition(from: self.imageNode.layer.position, to: location, duration: 0.25, removeOnCompletion: false, completion: { _ in
itemCompleted = true
internalCompletion()
})
self.imageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
} else {
self.imageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.35, removeOnCompletion: false, completion: { _ in
itemCompleted = true
internalCompletion()
})
}
}
func updateItem(_ item: StickerPackItem) {
var animateIn = false
if let _ = self.item {
animateIn = true
let previousImageNode = self.imageNode
previousImageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
previousImageNode.layer.animateSpring(from: 1.0 as NSNumber, to: 0.4 as NSNumber, keyPath: "transform.scale", duration: 0.4, damping: 88.0, removeOnCompletion: false, completion: { [weak previousImageNode] _ in
previousImageNode?.removeFromSupernode()
})
self.imageNode = TransformImageNode()
self.textNode = ASTextNode()
self.imageNode.addSubnode(self.textNode)
self.addSubnode(self.imageNode)
}
self.item = item
for case let .Sticker(text, _, _) in item.file.attributes {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black)
break
}
self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false))
if let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
if animateIn {
self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.imageNode.layer.animateSpring(from: 0.5 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.7, damping: 88.0)
}
}
}