mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
151 lines
6.9 KiB
Swift
151 lines
6.9 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import SwiftSignalKit
|
|
import UniversalMediaPlayer
|
|
import AccountContext
|
|
import PhotoResources
|
|
|
|
public enum ChatBubbleVideoDecorationContentMode {
|
|
case aspectFit
|
|
case aspectFill
|
|
}
|
|
|
|
public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
|
private let nativeSize: CGSize
|
|
private let contentMode: ChatBubbleVideoDecorationContentMode
|
|
|
|
public let corners: ImageCorners
|
|
public let backgroundNode: ASDisplayNode? = nil
|
|
public let contentContainerNode: ASDisplayNode
|
|
public let foregroundNode: ASDisplayNode? = nil
|
|
|
|
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
|
|
|
private var validLayoutSize: CGSize?
|
|
|
|
public init(corners: ImageCorners, nativeSize: CGSize, contentMode: ChatBubbleVideoDecorationContentMode, backgroundColor: UIColor) {
|
|
self.corners = corners
|
|
self.nativeSize = nativeSize
|
|
self.contentMode = contentMode
|
|
|
|
self.contentContainerNode = ASDisplayNode()
|
|
self.contentContainerNode.backgroundColor = backgroundColor
|
|
self.contentContainerNode.clipsToBounds = true
|
|
|
|
self.updateCorners(corners)
|
|
}
|
|
|
|
public func updateCorners(_ corners: ImageCorners) {
|
|
if isRoundEqualCorners(corners) {
|
|
self.contentContainerNode.cornerRadius = corners.topLeft.radius
|
|
self.contentContainerNode.layer.mask = nil
|
|
} else {
|
|
self.contentContainerNode.cornerRadius = 0
|
|
|
|
let boundingSize: CGSize = CGSize(width: max(corners.topLeft.radius, corners.bottomLeft.radius) + max(corners.topRight.radius, corners.bottomRight.radius), height: max(corners.topLeft.radius, corners.topRight.radius) + max(corners.bottomLeft.radius, corners.bottomRight.radius))
|
|
let size: CGSize = CGSize(width: boundingSize.width + corners.extendedEdges.left + corners.extendedEdges.right, height: boundingSize.height + corners.extendedEdges.top + corners.extendedEdges.bottom)
|
|
let arguments = TransformImageArguments(corners: corners, imageSize: size, boundingSize: boundingSize, intrinsicInsets: UIEdgeInsets())
|
|
guard let context = DrawingContext(size: size, clear: true) else {
|
|
return
|
|
}
|
|
context.withContext { ctx in
|
|
ctx.setFillColor(UIColor.black.cgColor)
|
|
ctx.fill(arguments.drawingRect)
|
|
}
|
|
addCorners(context, arguments: arguments)
|
|
|
|
if let maskImage = context.generateImage() {
|
|
let mask = CALayer()
|
|
mask.contents = maskImage.cgImage
|
|
mask.contentsScale = maskImage.scale
|
|
mask.contentsCenter = CGRect(x: max(corners.topLeft.radius, corners.bottomLeft.radius) / maskImage.size.width, y: max(corners.topLeft.radius, corners.topRight.radius) / maskImage.size.height, width: (maskImage.size.width - max(corners.topLeft.radius, corners.bottomLeft.radius) - max(corners.topRight.radius, corners.bottomRight.radius)) / maskImage.size.width, height: (maskImage.size.height - max(corners.topLeft.radius, corners.topRight.radius) - max(corners.bottomLeft.radius, corners.bottomRight.radius)) / maskImage.size.height)
|
|
|
|
self.contentContainerNode.layer.mask = mask
|
|
self.contentContainerNode.layer.mask?.frame = self.contentContainerNode.bounds
|
|
}
|
|
}
|
|
}
|
|
|
|
public func updateContentNode(_ contentNode: (UniversalVideoContentNode & ASDisplayNode)?) {
|
|
if self.contentNode !== contentNode {
|
|
let previous = self.contentNode
|
|
self.contentNode = contentNode
|
|
|
|
if let previous = previous {
|
|
if previous.supernode === self.contentContainerNode {
|
|
previous.removeFromSupernode()
|
|
}
|
|
}
|
|
|
|
if let contentNode = contentNode {
|
|
if contentNode.supernode !== self.contentContainerNode {
|
|
self.contentContainerNode.addSubnode(contentNode)
|
|
if let size = self.validLayoutSize {
|
|
var scaledSize: CGSize
|
|
switch self.contentMode {
|
|
case .aspectFit:
|
|
scaledSize = self.nativeSize.aspectFitted(size)
|
|
case .aspectFill:
|
|
scaledSize = self.nativeSize.aspectFilled(size)
|
|
}
|
|
if abs(scaledSize.width - size.width) < 2.0 {
|
|
scaledSize.width = size.width
|
|
}
|
|
if abs(scaledSize.height - size.height) < 2.0 {
|
|
scaledSize.height = size.height
|
|
}
|
|
|
|
contentNode.frame = CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize)
|
|
contentNode.updateLayout(size: scaledSize, transition: .immediate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
|
}
|
|
|
|
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
|
self.validLayoutSize = size
|
|
|
|
let bounds = CGRect(origin: CGPoint(), size: size)
|
|
if let backgroundNode = self.backgroundNode {
|
|
transition.updateFrame(node: backgroundNode, frame: bounds)
|
|
}
|
|
if let foregroundNode = self.foregroundNode {
|
|
transition.updateFrame(node: foregroundNode, frame: bounds)
|
|
}
|
|
transition.updateFrame(node: self.contentContainerNode, frame: bounds)
|
|
if let maskLayer = self.contentContainerNode.layer.mask {
|
|
transition.updateFrame(layer: maskLayer, frame: bounds)
|
|
}
|
|
if let contentNode = self.contentNode {
|
|
var scaledSize: CGSize
|
|
switch self.contentMode {
|
|
case .aspectFit:
|
|
scaledSize = self.nativeSize.aspectFitted(size)
|
|
case .aspectFill:
|
|
scaledSize = self.nativeSize.aspectFilled(size)
|
|
}
|
|
if abs(scaledSize.width - size.width) < 2.0 {
|
|
scaledSize.width = size.width
|
|
}
|
|
if abs(scaledSize.height - size.height) < 2.0 {
|
|
scaledSize.height = size.height
|
|
}
|
|
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize))
|
|
contentNode.updateLayout(size: scaledSize, transition: transition)
|
|
}
|
|
}
|
|
|
|
public func setStatus(_ status: Signal<MediaPlayerStatus?, NoError>) {
|
|
}
|
|
|
|
public func tap() {
|
|
}
|
|
}
|
|
|