mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
[WIP] Reactions
This commit is contained in:
parent
fb0824ed8b
commit
f1e4e2dc7b
35 changed files with 1713 additions and 489 deletions
|
|
@ -32,10 +32,13 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
public var currentFrameCount: Int {
|
||||
get {
|
||||
guard let lottieInstance = self.lottieInstance else {
|
||||
if let lottieInstance = self.lottieInstance {
|
||||
return Int(lottieInstance.frameCount)
|
||||
} else if let videoSource = self.videoSource {
|
||||
return Int(videoSource.frameRate)
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
return Int(lottieInstance.frameCount)
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +67,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
private var playbackSize: CGSize?
|
||||
|
||||
private var lottieInstance: LottieInstance?
|
||||
private var videoSource: AnimatedStickerFrameSource?
|
||||
private var frameIndex: Int = 0
|
||||
private var playbackMode: AnimatedStickerPlaybackMode = .loop
|
||||
|
||||
|
|
@ -99,23 +103,30 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
guard let strongSelf = self, let path = path else {
|
||||
return
|
||||
}
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else {
|
||||
return
|
||||
|
||||
if source.isVideo {
|
||||
if let videoSource = makeVideoStickerDirectFrameSource(queue: DirectAnimatedStickerNode.sharedQueue, path: path, width: width, height: height, cachePathPrefix: nil, unpremultiplyAlpha: false) {
|
||||
strongSelf.setupPlayback(videoSource: videoSource)
|
||||
}
|
||||
} else {
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path)) else {
|
||||
return
|
||||
}
|
||||
|
||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
||||
|
||||
guard let lottieInstance = LottieInstance(data: decompressedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
|
||||
print("Could not load sticker data")
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.setupPlayback(lottieInstance: lottieInstance)
|
||||
}
|
||||
|
||||
let decompressedData = TGGUnzipData(data, 8 * 1024 * 1024) ?? data
|
||||
|
||||
guard let lottieInstance = LottieInstance(data: decompressedData, fitzModifier: .none, colorReplacements: nil, cacheKey: "") else {
|
||||
print("Could not load sticker data")
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.setupPlayback(lottieInstance: lottieInstance)
|
||||
})
|
||||
}
|
||||
|
||||
private func updatePlayback() {
|
||||
let isPlaying = self.visibility && self.lottieInstance != nil
|
||||
let isPlaying = self.visibility && (self.lottieInstance != nil || self.videoSource != nil)
|
||||
if self.isPlaying != isPlaying {
|
||||
self.isPlaying = isPlaying
|
||||
|
||||
|
|
@ -132,8 +143,15 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
|
||||
private func startNextFrameTimerIfNeeded() {
|
||||
if self.nextFrameTimer == nil, let lottieInstance = self.lottieInstance, self.frameImages[self.frameIndex] != nil {
|
||||
let nextFrameTimer = SwiftSignalKit.Timer(timeout: 1.0 / Double(lottieInstance.frameRate), repeat: false, completion: { [weak self] in
|
||||
var frameRate: Double?
|
||||
if let lottieInstance = self.lottieInstance {
|
||||
frameRate = Double(lottieInstance.frameRate)
|
||||
} else if let videoSource = self.videoSource {
|
||||
frameRate = Double(videoSource.frameRate)
|
||||
}
|
||||
|
||||
if self.nextFrameTimer == nil, let frameRate = frameRate, self.frameImages[self.frameIndex] != nil {
|
||||
let nextFrameTimer = SwiftSignalKit.Timer(timeout: 1.0 / frameRate, repeat: false, completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
|
@ -146,11 +164,17 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
|
||||
private func advanceFrameIfPossible() {
|
||||
guard let lottieInstance = self.lottieInstance else {
|
||||
var frameCount: Int?
|
||||
if let lottieInstance = self.lottieInstance {
|
||||
frameCount = Int(lottieInstance.frameCount)
|
||||
} else if let videoSource = self.videoSource {
|
||||
frameCount = Int(videoSource.frameCount)
|
||||
}
|
||||
guard let frameCount = frameCount else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.frameIndex == Int(lottieInstance.frameCount) - 1 {
|
||||
if self.frameIndex == frameCount - 1 {
|
||||
switch self.playbackMode {
|
||||
case .loop:
|
||||
self.completed(false)
|
||||
|
|
@ -176,7 +200,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
}
|
||||
|
||||
let nextFrameIndex = (self.frameIndex + 1) % Int(lottieInstance.frameCount)
|
||||
let nextFrameIndex = (self.frameIndex + 1) % frameCount
|
||||
self.frameIndex = nextFrameIndex
|
||||
|
||||
self.updateFrameImageIfNeeded()
|
||||
|
|
@ -184,13 +208,19 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
|
||||
private func updateFrameImageIfNeeded() {
|
||||
guard let lottieInstance = self.lottieInstance else {
|
||||
var frameCount: Int?
|
||||
if let lottieInstance = self.lottieInstance {
|
||||
frameCount = Int(lottieInstance.frameCount)
|
||||
} else if let videoSource = self.videoSource {
|
||||
frameCount = Int(videoSource.frameCount)
|
||||
}
|
||||
guard let frameCount = frameCount else {
|
||||
return
|
||||
}
|
||||
|
||||
var allowedIndices: [Int] = []
|
||||
for i in 0 ..< 2 {
|
||||
let mappedIndex = (self.frameIndex + i) % Int(lottieInstance.frameCount)
|
||||
let mappedIndex = (self.frameIndex + i) % frameCount
|
||||
allowedIndices.append(mappedIndex)
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +243,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
if let image = self.frameImages[self.frameIndex] {
|
||||
self.layer.contents = image.cgImage
|
||||
|
||||
self.frameUpdated(self.frameIndex, Int(lottieInstance.frameCount))
|
||||
self.frameUpdated(self.frameIndex, frameCount)
|
||||
|
||||
if !self.didComplete {
|
||||
self.startNextFrameTimerIfNeeded()
|
||||
|
|
@ -227,20 +257,29 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
}
|
||||
|
||||
private func updateLoadFrameTasks() {
|
||||
guard let lottieInstance = self.lottieInstance else {
|
||||
var frameCount: Int?
|
||||
if let lottieInstance = self.lottieInstance {
|
||||
frameCount = Int(lottieInstance.frameCount)
|
||||
} else if let videoSource = self.videoSource {
|
||||
frameCount = Int(videoSource.frameCount)
|
||||
}
|
||||
guard let frameCount = frameCount else {
|
||||
return
|
||||
}
|
||||
|
||||
let frameIndex = self.frameIndex % Int(lottieInstance.frameCount)
|
||||
let frameIndex = self.frameIndex % frameCount
|
||||
if self.frameImages[frameIndex] == nil {
|
||||
self.maybeStartLoadFrameTask(frameIndex: frameIndex)
|
||||
} else {
|
||||
self.maybeStartLoadFrameTask(frameIndex: (frameIndex + 1) % Int(lottieInstance.frameCount))
|
||||
self.maybeStartLoadFrameTask(frameIndex: (frameIndex + 1) % frameCount)
|
||||
}
|
||||
}
|
||||
|
||||
private func maybeStartLoadFrameTask(frameIndex: Int) {
|
||||
guard let lottieInstance = self.lottieInstance, let playbackSize = self.playbackSize else {
|
||||
guard self.lottieInstance != nil || self.videoSource != nil else {
|
||||
return
|
||||
}
|
||||
guard let playbackSize = self.playbackSize else {
|
||||
return
|
||||
}
|
||||
if self.loadFrameTasks[frameIndex] != nil {
|
||||
|
|
@ -250,14 +289,27 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
let task = LoadFrameTask()
|
||||
self.loadFrameTasks[frameIndex] = task
|
||||
|
||||
let lottieInstance = self.lottieInstance
|
||||
let videoSource = self.videoSource
|
||||
|
||||
DirectAnimatedStickerNode.sharedQueue.async { [weak self] in
|
||||
var image: UIImage?
|
||||
|
||||
if !task.isCancelled {
|
||||
let drawingContext = DrawingContext(size: playbackSize, scale: 1.0, opaque: false, clear: false)
|
||||
lottieInstance.renderFrame(with: Int32(frameIndex), into: drawingContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(drawingContext.scaledSize.width), height: Int32(drawingContext.scaledSize.height), bytesPerRow: Int32(drawingContext.bytesPerRow))
|
||||
|
||||
image = drawingContext.generateImage()
|
||||
if let lottieInstance = lottieInstance {
|
||||
let drawingContext = DrawingContext(size: playbackSize, scale: 1.0, opaque: false, clear: false)
|
||||
lottieInstance.renderFrame(with: Int32(frameIndex), into: drawingContext.bytes.assumingMemoryBound(to: UInt8.self), width: Int32(drawingContext.scaledSize.width), height: Int32(drawingContext.scaledSize.height), bytesPerRow: Int32(drawingContext.bytesPerRow))
|
||||
|
||||
image = drawingContext.generateImage()
|
||||
} else if let videoSource = videoSource {
|
||||
if let frame = videoSource.takeFrame(draw: true) {
|
||||
let drawingContext = DrawingContext(size: CGSize(width: frame.width, height: frame.height), scale: 1.0, opaque: false, clear: false, bytesPerRow: frame.bytesPerRow)
|
||||
|
||||
frame.data.copyBytes(to: drawingContext.bytes.assumingMemoryBound(to: UInt8.self), from: 0 ..< min(frame.data.count, drawingContext.length))
|
||||
|
||||
image = drawingContext.generateImage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().async {
|
||||
|
|
@ -284,6 +336,12 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||
self.updatePlayback()
|
||||
}
|
||||
|
||||
private func setupPlayback(videoSource: AnimatedStickerFrameSource) {
|
||||
self.videoSource = videoSource
|
||||
|
||||
self.updatePlayback()
|
||||
}
|
||||
|
||||
public func reset() {
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue