mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Video Stickers Improvements
This commit is contained in:
parent
cc5de9372f
commit
7e9fea5c48
@ -22,6 +22,7 @@ swift_library(
|
||||
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||
"//submodules/SoftwareVideo:SoftwareVideo",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -12,6 +12,7 @@ import StickerResources
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import SoftwareVideo
|
||||
|
||||
public struct ItemListStickerPackItemEditing: Equatable {
|
||||
public var editable: Bool
|
||||
@ -121,7 +122,7 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
|
||||
|
||||
public enum StickerPackThumbnailItem: Equatable {
|
||||
case still(TelegramMediaImageRepresentation)
|
||||
case animated(MediaResource, PixelDimensions)
|
||||
case animated(MediaResource, PixelDimensions, Bool)
|
||||
|
||||
public static func ==(lhs: StickerPackThumbnailItem, rhs: StickerPackThumbnailItem) -> Bool {
|
||||
switch lhs {
|
||||
@ -131,8 +132,8 @@ public enum StickerPackThumbnailItem: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .animated(lhsResource, lhsDimensions):
|
||||
if case let .animated(rhsResource, rhsDimensions) = rhs, lhsResource.isEqual(to: rhsResource), lhsDimensions == rhsDimensions {
|
||||
case let .animated(lhsResource, lhsDimensions, lhsIsVideo):
|
||||
if case let .animated(rhsResource, rhsDimensions, rhsIsVideo) = rhs, lhsResource.isEqual(to: rhsResource), lhsDimensions == rhsDimensions, lhsIsVideo == rhsIsVideo {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -158,6 +159,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
fileprivate let imageNode: TransformImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let unreadNode: ASImageNode
|
||||
private let titleNode: TextNode
|
||||
@ -471,16 +473,15 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = item.packInfo.thumbnail {
|
||||
if item.packInfo.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
if item.packInfo.flags.contains(.isAnimated) || item.packInfo.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, item.packInfo.flags.contains(.isVideo))
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
} else if let item = item.topItem {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -507,7 +508,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource, nilIfEmpty: true)
|
||||
}
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, _):
|
||||
imageSize = imageBoundingSize
|
||||
|
||||
if fileUpdated {
|
||||
@ -745,29 +746,51 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
let boundingSize = CGSize(width: 34.0, height: 34.0)
|
||||
if let thumbnailItem = thumbnailItem, let imageSize = imageSize {
|
||||
let imageFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset + editingOffset + 15.0 + floor((boundingSize.width - imageSize.width) / 2.0), y: floor((layout.contentSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
|
||||
var thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
switch thumbnailItem {
|
||||
case let .still(representation):
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
thumbnailDimensions = representation.dimensions
|
||||
case let .animated(resource, _):
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let current = strongSelf.animationNode {
|
||||
animationNode = current
|
||||
case let .animated(resource, _, isVideo):
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = strongSelf.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
videoNode = VideoStickerNode()
|
||||
strongSelf.videoNode = videoNode
|
||||
strongSelf.addSubnode(videoNode)
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: item.account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
videoNode.updateLayout(size: imageFrame.size)
|
||||
videoNode.update(isPlaying: strongSelf.visibility != .none && item.playAnimatedStickers)
|
||||
videoNode.isHidden = !item.playAnimatedStickers
|
||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||
if let videoNode = strongSelf.videoNode {
|
||||
transition.updateFrame(node: videoNode, frame: imageFrame)
|
||||
}
|
||||
} else {
|
||||
animationNode = AnimatedStickerNode()
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource), width: 80, height: 80, mode: .cached)
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||
if let animationNode = strongSelf.animationNode {
|
||||
transition.updateFrame(node: animationNode, frame: imageFrame)
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let current = strongSelf.animationNode {
|
||||
animationNode = current
|
||||
} else {
|
||||
animationNode = AnimatedStickerNode()
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource), width: 80, height: 80, mode: .cached)
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||
if let animationNode = strongSelf.animationNode {
|
||||
transition.updateFrame(node: animationNode, frame: imageFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,19 +307,46 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
||||
let bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
|
||||
let bytesPerRowA = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 2)
|
||||
|
||||
var base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
||||
var requiresAlphaMultiplication = false
|
||||
|
||||
var base: UnsafeMutableRawPointer
|
||||
if case .YUVA = frame.pixelFormat {
|
||||
requiresAlphaMultiplication = true
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!
|
||||
if bytesPerRowA == frame.lineSize[3] {
|
||||
memcpy(base, frame.data[3]!, bytesPerRowA * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[3]!
|
||||
let lineSize = Int(frame.lineSize[3])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowA)
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
||||
if bytesPerRowY == frame.lineSize[0] {
|
||||
memcpy(base, frame.data[0]!, bytesPerRowY * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[0]!
|
||||
let linesize = Int(frame.lineSize[0])
|
||||
let lineSize = Int(frame.lineSize[0])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, linesize)
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowY)
|
||||
src = src.advanced(by: linesize)
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
|
||||
if requiresAlphaMultiplication {
|
||||
var y = vImage_Buffer(data: CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!, height: vImagePixelCount(frame.height), width: vImagePixelCount(bytesPerRowY), rowBytes: bytesPerRowY)
|
||||
var a = vImage_Buffer(data: CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!, height: vImagePixelCount(frame.height), width: vImagePixelCount(bytesPerRowY), rowBytes: bytesPerRowA)
|
||||
let _ = vImagePremultiplyData_Planar8(&y, &a, &y, vImage_Flags(kvImageDoNotTile))
|
||||
}
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)!
|
||||
if bytesPerRowUV == frame.lineSize[1] * 2 {
|
||||
@ -327,27 +354,11 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
||||
} else {
|
||||
var dest = base
|
||||
var src = dstPlane
|
||||
let linesize = Int(frame.lineSize[1]) * 2
|
||||
let lineSize = Int(frame.lineSize[1]) * 2
|
||||
for _ in 0 ..< Int(frame.height / 2) {
|
||||
memcpy(dest, src, linesize)
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowUV)
|
||||
src = src.advanced(by: linesize)
|
||||
}
|
||||
}
|
||||
|
||||
if case .YUVA = frame.pixelFormat {
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!
|
||||
if bytesPerRowA == frame.lineSize[3] {
|
||||
memcpy(base, frame.data[3]!, bytesPerRowA * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[3]!
|
||||
let linesize = Int(frame.lineSize[3])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, linesize)
|
||||
dest = dest.advanced(by: bytesPerRowA)
|
||||
src = src.advanced(by: linesize)
|
||||
}
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,9 @@ public struct StickerPackCollectionInfoFlags: OptionSet {
|
||||
if flags.contains(StickerPackCollectionInfoFlags.isAnimated) {
|
||||
rawValue |= StickerPackCollectionInfoFlags.isAnimated.rawValue
|
||||
}
|
||||
if flags.contains(StickerPackCollectionInfoFlags.isVideo) {
|
||||
rawValue |= StickerPackCollectionInfoFlags.isVideo.rawValue
|
||||
}
|
||||
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
@ -31,6 +34,7 @@ public struct StickerPackCollectionInfoFlags: OptionSet {
|
||||
public static let isMasks = StickerPackCollectionInfoFlags(rawValue: 1 << 0)
|
||||
public static let isOfficial = StickerPackCollectionInfoFlags(rawValue: 1 << 1)
|
||||
public static let isAnimated = StickerPackCollectionInfoFlags(rawValue: 1 << 2)
|
||||
public static let isVideo = StickerPackCollectionInfoFlags(rawValue: 1 << 3)
|
||||
}
|
||||
|
||||
|
||||
|
@ -43,6 +43,9 @@ extension StickerPackCollectionInfo {
|
||||
if (flags & (1 << 5)) != 0 {
|
||||
setFlags.insert(.isAnimated)
|
||||
}
|
||||
if (flags & (1 << 6)) != 0 {
|
||||
setFlags.insert(.isVideo)
|
||||
}
|
||||
|
||||
var thumbnailRepresentation: TelegramMediaImageRepresentation?
|
||||
var immediateThumbnailData: Data?
|
||||
|
@ -84,7 +84,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
private let scalingNode: ASDisplayNode
|
||||
private let imageNode: TransformImageNode
|
||||
private var animatedStickerNode: AnimatedStickerNode?
|
||||
private var videoStickerNode: VideoStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let highlightNode: ASImageNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
@ -109,7 +109,9 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
didSet {
|
||||
if self.visibilityStatus != oldValue {
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
self.animatedStickerNode?.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
let visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
self.videoNode?.update(isPlaying: visibility)
|
||||
self.animatedStickerNode?.visibility = visibility
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,16 +193,15 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = info.thumbnail {
|
||||
if info.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, info.flags.contains(.isVideo))
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
} else if let item = item {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -225,30 +226,54 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 6.0), imageSize: imageSize, boundingSize: boundingImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: representation.resource, nilIfEmpty: true))
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, isVideo):
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: boundingImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: resource, animated: true, nilIfEmpty: true))
|
||||
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
} else {
|
||||
animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.scalingNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = self.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
self.scalingNode.addSubnode(animatedStickerNode)
|
||||
videoNode = VideoStickerNode()
|
||||
videoNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.videoNode = videoNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.scalingNode.insertSubnode(videoNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.scalingNode.addSubnode(videoNode)
|
||||
}
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
} else {
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
} else {
|
||||
animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.scalingNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.scalingNode.addSubnode(animatedStickerNode)
|
||||
}
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
if let resourceReference = resourceReference {
|
||||
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start())
|
||||
@ -289,8 +314,9 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = self.imageNode.frame
|
||||
animatedStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let videoNode = self.videoStickerNode {
|
||||
if let videoNode = self.videoNode {
|
||||
videoNode.frame = self.imageNode.frame
|
||||
videoNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.bounds = CGRect(origin: CGPoint(), size: boundingImageSize)
|
||||
@ -338,7 +364,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
}
|
||||
|
||||
override func snapshotForReordering() -> UIView? {
|
||||
if let account = account, let thumbnailItem = self.currentThumbnailItem {
|
||||
if let account = self.account, let thumbnailItem = self.currentThumbnailItem {
|
||||
var imageSize = boundingImageSize
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
let containerNode = ASDisplayNode()
|
||||
@ -348,6 +374,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
|
||||
var snapshotImageNode: TransformImageNode?
|
||||
var snapshotAnimationNode: AnimatedStickerNode?
|
||||
var snapshotVideoNode: VideoStickerNode?
|
||||
switch thumbnailItem {
|
||||
case let .still(representation):
|
||||
imageSize = representation.dimensions.cgSize.aspectFitted(boundingImageSize)
|
||||
@ -359,16 +386,28 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
scalingNode.addSubnode(imageNode)
|
||||
|
||||
snapshotImageNode = imageNode
|
||||
case let .animated(resource, _):
|
||||
let animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
scalingNode.addSubnode(animatedStickerNode)
|
||||
|
||||
animatedStickerNode.cloneCurrentFrame(from: self.animatedStickerNode)
|
||||
animatedStickerNode.play(fromIndex: self.animatedStickerNode?.currentFrameIndex)
|
||||
|
||||
snapshotAnimationNode = animatedStickerNode
|
||||
case let .animated(resource, _, isVideo):
|
||||
if isVideo {
|
||||
let videoNode = VideoStickerNode()
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
scalingNode.addSubnode(videoNode)
|
||||
|
||||
snapshotVideoNode = videoNode
|
||||
} else {
|
||||
let animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
scalingNode.addSubnode(animatedStickerNode)
|
||||
|
||||
animatedStickerNode.cloneCurrentFrame(from: self.animatedStickerNode)
|
||||
animatedStickerNode.play(fromIndex: self.animatedStickerNode?.currentFrameIndex)
|
||||
|
||||
snapshotAnimationNode = animatedStickerNode
|
||||
}
|
||||
}
|
||||
|
||||
containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)
|
||||
@ -388,6 +427,10 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = imageFrame
|
||||
animatedStickerNode.updateLayout(size: imageFrame.size)
|
||||
}
|
||||
if let videoStickerNode = snapshotVideoNode {
|
||||
videoStickerNode.frame = imageFrame
|
||||
videoStickerNode.updateLayout(size: imageFrame.size)
|
||||
}
|
||||
|
||||
let expanded = self.currentExpanded
|
||||
let scale = expanded ? 1.0 : boundingImageScale
|
||||
|
@ -1733,7 +1733,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, MessageReference(item.message), item.message.peers[openPeerId])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import MergeLists
|
||||
import SoftwareVideo
|
||||
|
||||
private let boundingSize = CGSize(width: 41.0, height: 41.0)
|
||||
private let boundingImageSize = CGSize(width: 28.0, height: 28.0)
|
||||
@ -154,6 +155,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
private let containerNode: ASDisplayNode
|
||||
private let imageNode: TransformImageNode
|
||||
private var animatedStickerNode: AnimatedStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let unreadNode: ASImageNode
|
||||
|
||||
@ -255,16 +257,16 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = info.thumbnail {
|
||||
if info.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, info.flags.contains(.isVideo))
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
} else if let item = item {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -284,30 +286,54 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: representation.resource, nilIfEmpty: true))
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, isVideo):
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: resource, animated: true, nilIfEmpty: true))
|
||||
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
} else {
|
||||
animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.containerNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = self.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
self.containerNode.addSubnode(animatedStickerNode)
|
||||
videoNode = VideoStickerNode()
|
||||
videoNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.videoNode = videoNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.containerNode.insertSubnode(videoNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.containerNode.addSubnode(videoNode)
|
||||
}
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
} else {
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
} else {
|
||||
animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.containerNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.containerNode.addSubnode(animatedStickerNode)
|
||||
}
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
if let resourceReference = resourceReference {
|
||||
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start())
|
||||
@ -328,6 +354,10 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = self.imageNode.frame
|
||||
animatedStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let videoStickerNode = self.videoNode {
|
||||
videoStickerNode.frame = self.imageNode.frame
|
||||
videoStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.bounds = CGRect(origin: CGPoint(), size: boundingImageSize)
|
||||
placeholderNode.position = self.imageNode.position
|
||||
|
Loading…
x
Reference in New Issue
Block a user