mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various improvements
This commit is contained in:
parent
a63a3074bd
commit
383ab9e479
Binary file not shown.
@ -112,7 +112,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
if source.isVideo {
|
if source.isVideo {
|
||||||
if let videoSource = makeVideoStickerDirectFrameSource(queue: DirectAnimatedStickerNode.sharedQueue, path: path, width: width, height: height, cachePathPrefix: nil, unpremultiplyAlpha: false) {
|
if let videoSource = makeVideoStickerDirectFrameSource(queue: DirectAnimatedStickerNode.sharedQueue, path: path, hintVP9: true, width: width, height: height, cachePathPrefix: nil, unpremultiplyAlpha: false) {
|
||||||
strongSelf.setupPlayback(videoSource: videoSource)
|
strongSelf.setupPlayback(videoSource: videoSource)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -273,8 +273,8 @@ private final class VideoStickerFrameSourceCache {
|
|||||||
|
|
||||||
private let useCache = true
|
private let useCache = true
|
||||||
|
|
||||||
public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? {
|
public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, hintVP9: Bool, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? {
|
||||||
return VideoStickerDirectFrameSource(queue: queue, path: path, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha)
|
return VideoStickerDirectFrameSource(queue: queue, path: path, isVP9: hintVP9, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
||||||
@ -290,7 +290,7 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
|||||||
public var duration: Double
|
public var duration: Double
|
||||||
fileprivate var currentFrame: Int
|
fileprivate var currentFrame: Int
|
||||||
|
|
||||||
private let source: SoftwareVideoSource?
|
private var source: FFMpegFileReader?
|
||||||
|
|
||||||
public var frameIndex: Int {
|
public var frameIndex: Int {
|
||||||
if self.frameCount == 0 {
|
if self.frameCount == 0 {
|
||||||
@ -300,7 +300,7 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public init?(queue: Queue, path: String, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool = true) {
|
public init?(queue: Queue, path: String, isVP9: Bool = true, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool = true) {
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.path = path
|
self.path = path
|
||||||
self.width = width
|
self.width = width
|
||||||
@ -329,12 +329,25 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
|||||||
self.frameCount = 1
|
self.frameCount = 1
|
||||||
self.duration = 0.0
|
self.duration = 0.0
|
||||||
} else {
|
} else {
|
||||||
let source = SoftwareVideoSource(path: path, hintVP9: true, unpremultiplyAlpha: unpremultiplyAlpha)
|
let source = FFMpegFileReader(
|
||||||
|
source: .file(path),
|
||||||
|
passthroughDecoder: false,
|
||||||
|
useHardwareAcceleration: false,
|
||||||
|
selectedStream: .mediaType(.video),
|
||||||
|
seek: nil,
|
||||||
|
maxReadablePts: nil
|
||||||
|
)
|
||||||
|
if let source {
|
||||||
self.source = source
|
self.source = source
|
||||||
|
self.frameRate = min(30, source.frameRate())
|
||||||
|
self.duration = source.duration().seconds
|
||||||
|
} else {
|
||||||
|
self.source = nil
|
||||||
|
self.frameRate = 30
|
||||||
|
self.duration = 0.0
|
||||||
|
}
|
||||||
self.image = nil
|
self.image = nil
|
||||||
self.frameRate = min(30, source.getFramerate())
|
|
||||||
self.frameCount = 0
|
self.frameCount = 0
|
||||||
self.duration = source.reportedDuration.seconds
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,32 +378,9 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
|||||||
} else if useCache, let cache = self.cache, let yuvData = cache.readUncompressedYuvaFrame(index: frameIndex) {
|
} else if useCache, let cache = self.cache, let yuvData = cache.readUncompressedYuvaFrame(index: frameIndex) {
|
||||||
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.width * 2, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.width * 2, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
||||||
} else if let source = self.source {
|
} else if let source = self.source {
|
||||||
let frameAndLoop = source.readFrame(maxPts: nil)
|
let frameAndLoop = source.readFrame(argb: true)
|
||||||
if frameAndLoop.0 == nil {
|
switch frameAndLoop {
|
||||||
if frameAndLoop.3 {
|
case let .frame(frame):
|
||||||
if self.frameCount == 0 {
|
|
||||||
if let cache = self.cache {
|
|
||||||
if cache.storedFrames == frameIndex {
|
|
||||||
self.frameCount = frameIndex
|
|
||||||
cache.storeFrameRateAndCount(frameRate: self.frameRate, frameCount: self.frameCount)
|
|
||||||
} else {
|
|
||||||
Logger.shared.log("VideoSticker", "Missed a frame? \(frameIndex) \(cache.storedFrames)")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.frameCount = frameIndex
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.currentFrame = 0
|
|
||||||
} else {
|
|
||||||
Logger.shared.log("VideoSticker", "Skipped a frame?")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let frame = frameAndLoop.0 else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var frameData = Data(count: self.bytesPerRow * self.height)
|
var frameData = Data(count: self.bytesPerRow * self.height)
|
||||||
frameData.withUnsafeMutableBytes { buffer -> Void in
|
frameData.withUnsafeMutableBytes { buffer -> Void in
|
||||||
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
|
||||||
@ -415,6 +405,39 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource {
|
|||||||
self.cache?.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
|
self.cache?.storeUncompressedRgbFrame(index: frameIndex, rgbData: frameData)
|
||||||
|
|
||||||
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount, multiplyAlpha: true)
|
return AnimatedStickerFrame(data: frameData, type: .argb, width: self.width, height: self.height, bytesPerRow: self.bytesPerRow, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount, multiplyAlpha: true)
|
||||||
|
case .endOfStream:
|
||||||
|
if self.frameCount == 0 {
|
||||||
|
if let cache = self.cache {
|
||||||
|
if cache.storedFrames == frameIndex {
|
||||||
|
self.frameCount = frameIndex
|
||||||
|
cache.storeFrameRateAndCount(frameRate: self.frameRate, frameCount: self.frameCount)
|
||||||
|
} else {
|
||||||
|
Logger.shared.log("VideoSticker", "Missed a frame? \(frameIndex) \(cache.storedFrames)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.frameCount = frameIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.currentFrame = 0
|
||||||
|
self.source = FFMpegFileReader(
|
||||||
|
source: .file(self.path),
|
||||||
|
passthroughDecoder: false,
|
||||||
|
useHardwareAcceleration: false,
|
||||||
|
selectedStream: .mediaType(.video),
|
||||||
|
seek: nil,
|
||||||
|
maxReadablePts: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
if let cache = self.cache {
|
||||||
|
if let yuvData = cache.readUncompressedYuvaFrame(index: self.currentFrame) {
|
||||||
|
return AnimatedStickerFrame(data: yuvData, type: .yuva, width: self.width, height: self.height, bytesPerRow: self.width * 2, index: frameIndex, isLastFrame: frameIndex == self.frameCount - 1, totalFrames: self.frameCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
case .waitingForMoreData, .error:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var emojiMarkup: TelegramMediaImage.EmojiMarkup?
|
private var emojiMarkup: TelegramMediaImage.EmojiMarkup?
|
||||||
|
|
||||||
|
private var videoFileDisposable: Disposable?
|
||||||
private var fileDisposable = MetaDisposable()
|
private var fileDisposable = MetaDisposable()
|
||||||
private var animationFile: TelegramMediaFile?
|
private var animationFile: TelegramMediaFile?
|
||||||
private var itemLayer: EmojiKeyboardItemLayer?
|
private var itemLayer: EmojiKeyboardItemLayer?
|
||||||
@ -32,6 +33,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
private var animationNode: AnimatedStickerNode?
|
private var animationNode: AnimatedStickerNode?
|
||||||
private let stickerFetchedDisposable = MetaDisposable()
|
private let stickerFetchedDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private var videoItemLayer: EmojiKeyboardItemLayer?
|
||||||
private var videoNode: UniversalVideoNode?
|
private var videoNode: UniversalVideoNode?
|
||||||
private var videoContent: NativeVideoContent?
|
private var videoContent: NativeVideoContent?
|
||||||
private let playbackStartDisposable = MetaDisposable()
|
private let playbackStartDisposable = MetaDisposable()
|
||||||
@ -55,6 +57,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
|
self.videoFileDisposable?.dispose()
|
||||||
self.fileDisposable.dispose()
|
self.fileDisposable.dispose()
|
||||||
self.stickerFetchedDisposable.dispose()
|
self.stickerFetchedDisposable.dispose()
|
||||||
self.playbackStartDisposable.dispose()
|
self.playbackStartDisposable.dispose()
|
||||||
@ -137,6 +140,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
self.videoLoopCount += 1
|
self.videoLoopCount += 1
|
||||||
if self.videoLoopCount >= maxVideoLoopCount {
|
if self.videoLoopCount >= maxVideoLoopCount {
|
||||||
self.itemLayer?.isVisibleForAnimations = false
|
self.itemLayer?.isVisibleForAnimations = false
|
||||||
|
self.videoItemLayer?.isVisibleForAnimations = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,6 +215,9 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
if videoContent.id != self.videoContent?.id {
|
if videoContent.id != self.videoContent?.id {
|
||||||
self.videoNode?.removeFromSupernode()
|
self.videoNode?.removeFromSupernode()
|
||||||
self.videoContent = videoContent
|
self.videoContent = videoContent
|
||||||
|
|
||||||
|
self.videoFileDisposable?.dispose()
|
||||||
|
self.videoFileDisposable = fetchedMediaResource(mediaBox: self.context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .avatar, reference: videoFileReference.resourceReference(videoFileReference.media.resource)).startStrict()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,6 +238,60 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.animationNode?.visibility = isVisible
|
self.animationNode?.visibility = isVisible
|
||||||
if isVisible, let videoContent = self.videoContent, self.videoLoopCount < maxVideoLoopCount {
|
if isVisible, let videoContent = self.videoContent, self.videoLoopCount < maxVideoLoopCount {
|
||||||
|
var useDirectCache = false
|
||||||
|
if self.internalSize.width <= 200.0 {
|
||||||
|
useDirectCache = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if useDirectCache {
|
||||||
|
if self.videoItemLayer == nil {
|
||||||
|
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(videoContent.fileReference.media))
|
||||||
|
let videoItemLayer = EmojiKeyboardItemLayer(
|
||||||
|
item: EmojiPagerContentComponent.Item(
|
||||||
|
animationData: animationData,
|
||||||
|
content: .animation(animationData),
|
||||||
|
itemFile: TelegramMediaFile.Accessor(videoContent.fileReference.media),
|
||||||
|
subgroupId: nil,
|
||||||
|
icon: .none,
|
||||||
|
tintMode: .none
|
||||||
|
),
|
||||||
|
context: self.context,
|
||||||
|
attemptSynchronousLoad: false,
|
||||||
|
content: .animation(animationData),
|
||||||
|
cache: self.context.animationCache,
|
||||||
|
renderer: self.context.animationRenderer,
|
||||||
|
placeholderColor: .clear,
|
||||||
|
blurredBadgeColor: .clear,
|
||||||
|
accentIconColor: .white,
|
||||||
|
pointSize: self.internalSize,
|
||||||
|
onUpdateDisplayPlaceholder: { _, _ in
|
||||||
|
}
|
||||||
|
)
|
||||||
|
videoItemLayer.onLoop = { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.videoLoopCount += 1
|
||||||
|
if self.videoLoopCount >= maxVideoLoopCount {
|
||||||
|
self.itemLayer?.isVisibleForAnimations = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.videoItemLayer = videoItemLayer
|
||||||
|
self.layer.addSublayer(videoItemLayer)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let videoItemLayer = self.videoItemLayer {
|
||||||
|
self.videoItemLayer = nil
|
||||||
|
videoItemLayer.removeFromSuperlayer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if useDirectCache {
|
||||||
|
if let videoNode = self.videoNode {
|
||||||
|
self.videoNode = nil
|
||||||
|
videoNode.removeFromSupernode()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if self.videoNode == nil {
|
if self.videoNode == nil {
|
||||||
let context = self.context
|
let context = self.context
|
||||||
let mediaManager = context.sharedContext.mediaManager
|
let mediaManager = context.sharedContext.mediaManager
|
||||||
@ -282,6 +343,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
self.addSubnode(videoNode)
|
self.addSubnode(videoNode)
|
||||||
self.videoNode = videoNode
|
self.videoNode = videoNode
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if let videoNode = self.videoNode {
|
} else if let videoNode = self.videoNode {
|
||||||
self.videoNode = nil
|
self.videoNode = nil
|
||||||
videoNode.removeFromSupernode()
|
videoNode.removeFromSupernode()
|
||||||
@ -289,6 +351,7 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
if self.videoLoopCount < maxVideoLoopCount {
|
if self.videoLoopCount < maxVideoLoopCount {
|
||||||
self.itemLayer?.isVisibleForAnimations = isVisible
|
self.itemLayer?.isVisibleForAnimations = isVisible
|
||||||
}
|
}
|
||||||
|
self.videoItemLayer?.isVisibleForAnimations = isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateLayout(size: CGSize, cornerRadius: CGFloat, transition: ContainedViewLayoutTransition) {
|
public func updateLayout(size: CGSize, cornerRadius: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
@ -301,6 +364,9 @@ public final class AvatarVideoNode: ASDisplayNode {
|
|||||||
videoNode.frame = CGRect(origin: .zero, size: size)
|
videoNode.frame = CGRect(origin: .zero, size: size)
|
||||||
videoNode.updateLayout(size: size, transition: transition)
|
videoNode.updateLayout(size: size, transition: transition)
|
||||||
}
|
}
|
||||||
|
if let videoItemLayer = self.videoItemLayer {
|
||||||
|
videoItemLayer.frame = CGRect(origin: .zero, size: size)
|
||||||
|
}
|
||||||
|
|
||||||
let itemSize = CGSize(width: size.width * 0.67, height: size.height * 0.67)
|
let itemSize = CGSize(width: size.width * 0.67, height: size.height * 0.67)
|
||||||
let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - itemSize.width) / 2.0), y: floorToScreenPixels((size.height - itemSize.height) / 2.0)), size: itemSize)
|
let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - itemSize.width) / 2.0), y: floorToScreenPixels((size.height - itemSize.height) / 2.0)), size: itemSize)
|
||||||
|
@ -1747,7 +1747,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
self.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize)
|
self.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if peer.smallProfileImage != nil && overrideImage == nil {
|
||||||
|
self.avatarNode.setPeerV2(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||||
|
} else {
|
||||||
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
self.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: isForumAvatar ? .roundedRect : .round, synchronousLoad: synchronousLoads, displayDimensions: CGSize(width: 60.0, height: 60.0))
|
||||||
|
}
|
||||||
|
|
||||||
if peer.isPremium && peer.id != item.context.account.peerId {
|
if peer.isPremium && peer.id != item.context.account.peerId {
|
||||||
let context = item.context
|
let context = item.context
|
||||||
|
@ -954,10 +954,10 @@ final class ChatSendMessageContextScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var customEffectResource: (FileMediaReference, MediaResource)?
|
var customEffectResource: (FileMediaReference, MediaResource)?
|
||||||
if let effectAnimation = messageEffect.effectAnimation {
|
if let effectAnimation = messageEffect.effectAnimation?._parse() {
|
||||||
customEffectResource = (FileMediaReference.standalone(media: effectAnimation), effectAnimation.resource)
|
customEffectResource = (FileMediaReference.standalone(media: effectAnimation), effectAnimation.resource)
|
||||||
} else {
|
} else {
|
||||||
let effectSticker = messageEffect.effectSticker
|
let effectSticker = messageEffect.effectSticker._parse()
|
||||||
if let effectFile = effectSticker.videoThumbnails.first {
|
if let effectFile = effectSticker.videoThumbnails.first {
|
||||||
customEffectResource = (FileMediaReference.standalone(media: effectSticker), effectFile.resource)
|
customEffectResource = (FileMediaReference.standalone(media: effectSticker), effectFile.resource)
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ final class MessageItemView: UIView {
|
|||||||
}
|
}
|
||||||
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
|
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
|
||||||
if let staticIcon = effect.staticIcon {
|
if let staticIcon = effect.staticIcon {
|
||||||
effectIconContent = .file(staticIcon)
|
effectIconContent = .file(staticIcon._parse())
|
||||||
} else {
|
} else {
|
||||||
effectIconContent = .text(effect.emoticon)
|
effectIconContent = .text(effect.emoticon)
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ final class NavigationTransitionCoordinator {
|
|||||||
private var currentCompletion: (() -> Void)?
|
private var currentCompletion: (() -> Void)?
|
||||||
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
|
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
|
||||||
|
|
||||||
|
private var frameRateLink: SharedDisplayLinkDriver.Link?
|
||||||
|
|
||||||
init(transition: NavigationTransition, isInteractive: Bool, isFlat: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
|
init(transition: NavigationTransition, isInteractive: Bool, isFlat: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
|
||||||
self.transition = transition
|
self.transition = transition
|
||||||
self.isInteractive = isInteractive
|
self.isInteractive = isInteractive
|
||||||
@ -114,6 +116,8 @@ final class NavigationTransitionCoordinator {
|
|||||||
|
|
||||||
self.maybeCreateNavigationBarTransition()
|
self.maybeCreateNavigationBarTransition()
|
||||||
self.updateProgress(0.0, transition: .immediate, completion: {})
|
self.updateProgress(0.0, transition: .immediate, completion: {})
|
||||||
|
|
||||||
|
self.frameRateLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { _ in })
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required init(coder aDecoder: NSCoder) {
|
||||||
|
@ -403,6 +403,22 @@ public final class FFMpegFileReader {
|
|||||||
deinit {
|
deinit {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func frameRate() -> Int {
|
||||||
|
if let stream = self.stream {
|
||||||
|
return Int(stream.info.fps.seconds)
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func duration() -> CMTime {
|
||||||
|
if let stream = self.stream {
|
||||||
|
return stream.info.duration
|
||||||
|
} else {
|
||||||
|
return .zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func readPacketInternal() -> FFMpegPacket? {
|
private func readPacketInternal() -> FFMpegPacket? {
|
||||||
guard let avFormatContext = self.avFormatContext else {
|
guard let avFormatContext = self.avFormatContext else {
|
||||||
return nil
|
return nil
|
||||||
@ -452,7 +468,7 @@ public final class FFMpegFileReader {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func readFrame() -> ReadFrameResult {
|
public func readFrame(argb: Bool = false) -> ReadFrameResult {
|
||||||
guard let stream = self.stream else {
|
guard let stream = self.stream else {
|
||||||
return .error
|
return .error
|
||||||
}
|
}
|
||||||
@ -461,7 +477,7 @@ public final class FFMpegFileReader {
|
|||||||
var result: MediaTrackFrame?
|
var result: MediaTrackFrame?
|
||||||
switch stream.decoder {
|
switch stream.decoder {
|
||||||
case let .video(decoder):
|
case let .video(decoder):
|
||||||
result = decoder.decode(ptsOffset: nil, forceARGB: false, unpremultiplyAlpha: false, displayImmediately: false)
|
result = decoder.decode(ptsOffset: nil, forceARGB: argb, unpremultiplyAlpha: false, displayImmediately: false)
|
||||||
case let .videoPassthrough(decoder):
|
case let .videoPassthrough(decoder):
|
||||||
result = decoder.decode()
|
result = decoder.decode()
|
||||||
case let .audio(decoder):
|
case let .audio(decoder):
|
||||||
|
@ -448,7 +448,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, userLocation:
|
|||||||
return signal
|
return signal
|
||||||
}
|
}
|
||||||
|
|
||||||
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
|
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, alternativeFileAndRange: Signal<(TelegramMediaFile, Range<Int64>), NoError>? = nil, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
|
||||||
let fullSizeResource = fileReference.media.resource
|
let fullSizeResource = fileReference.media.resource
|
||||||
var reducedSizeResource: MediaResource?
|
var reducedSizeResource: MediaResource?
|
||||||
if let videoThumbnail = fileReference.media.videoThumbnails.first {
|
if let videoThumbnail = fileReference.media.videoThumbnails.first {
|
||||||
@ -1627,7 +1627,7 @@ public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, previewSourceFileReference: FileMediaReference? = nil, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
|
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, previewSourceFileReference: FileMediaReference? = nil, imageReference: ImageMediaReference? = nil, alternativeFileAndRange: Signal<(TelegramMediaFile, Range<Int64>), NoError>? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
|
||||||
let signal: Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError>
|
let signal: Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError>
|
||||||
if let imageReference = imageReference {
|
if let imageReference = imageReference {
|
||||||
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad, forceThumbnail: blurred)
|
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad, forceThumbnail: blurred)
|
||||||
@ -1638,7 +1638,7 @@ public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaR
|
|||||||
return Tuple(thumbnailData, fullSizeData.flatMap({ Tuple($0, "") }), fullSizeComplete)
|
return Tuple(thumbnailData, fullSizeData.flatMap({ Tuple($0, "") }), fullSizeComplete)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, fileReference: videoReference, previewSourceFileReference: previewSourceFileReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
|
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, fileReference: videoReference, previewSourceFileReference: previewSourceFileReference, alternativeFileAndRange: alternativeFileAndRange, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal
|
return signal
|
||||||
|
@ -1893,7 +1893,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
for i in 0 ..< 2 {
|
for i in 0 ..< 2 {
|
||||||
let groupId = i == 0 ? "reactions" : "stickers"
|
let groupId = i == 0 ? "reactions" : "stickers"
|
||||||
for item in i == 0 ? reactionEffects : stickerEffects {
|
for item in i == 0 ? reactionEffects : stickerEffects {
|
||||||
let itemFile: TelegramMediaFile = item.effectSticker
|
let itemFile = item.effectSticker
|
||||||
|
|
||||||
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
|
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
|
||||||
if itemFile.isCustomTemplateEmoji {
|
if itemFile.isCustomTemplateEmoji {
|
||||||
@ -1917,11 +1917,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
|
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
|
||||||
let resultItem = EmojiPagerContentComponent.Item(
|
let resultItem = EmojiPagerContentComponent.Item(
|
||||||
animationData: animationData,
|
animationData: animationData,
|
||||||
content: .animation(animationData),
|
content: .animation(animationData),
|
||||||
itemFile: TelegramMediaFile.Accessor(itemFile),
|
itemFile: itemFile,
|
||||||
subgroupId: nil,
|
subgroupId: nil,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
tintMode: tintMode
|
tintMode: tintMode
|
||||||
@ -2257,7 +2257,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
for i in 0 ..< 2 {
|
for i in 0 ..< 2 {
|
||||||
let groupId = i == 0 ? "reactions" : "stickers"
|
let groupId = i == 0 ? "reactions" : "stickers"
|
||||||
for item in i == 0 ? reactionEffects : stickerEffects {
|
for item in i == 0 ? reactionEffects : stickerEffects {
|
||||||
let itemFile: TelegramMediaFile = item.effectSticker
|
let itemFile = item.effectSticker
|
||||||
|
|
||||||
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
|
var tintMode: EmojiPagerContentComponent.Item.TintMode = .none
|
||||||
if itemFile.isCustomTemplateEmoji {
|
if itemFile.isCustomTemplateEmoji {
|
||||||
@ -2281,11 +2281,11 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
|
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
|
||||||
let resultItem = EmojiPagerContentComponent.Item(
|
let resultItem = EmojiPagerContentComponent.Item(
|
||||||
animationData: animationData,
|
animationData: animationData,
|
||||||
content: .animation(animationData),
|
content: .animation(animationData),
|
||||||
itemFile: TelegramMediaFile.Accessor(itemFile),
|
itemFile: itemFile,
|
||||||
subgroupId: nil,
|
subgroupId: nil,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
tintMode: tintMode
|
tintMode: tintMode
|
||||||
|
@ -976,7 +976,7 @@ func applyLoadMessageHistoryThreadsResults(accountPeerId: PeerId, transaction: T
|
|||||||
transaction.replaceMessageTagSummary(peerId: result.peerId, threadId: item.threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, customTag: nil, count: item.unreadReactionsCount, maxId: item.topMessage)
|
transaction.replaceMessageTagSummary(peerId: result.peerId, threadId: item.threadId, tagMask: .unseenReaction, namespace: Namespaces.Message.Cloud, customTag: nil, count: item.unreadReactionsCount, maxId: item.topMessage)
|
||||||
|
|
||||||
if item.topMessage != 0 {
|
if item.topMessage != 0 {
|
||||||
transaction.removeHole(peerId: result.peerId, threadId: item.threadId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: item.topMessage ... (Int32.max - 1))
|
//transaction.removeHole(peerId: result.peerId, threadId: item.threadId, namespace: Namespaces.Message.Cloud, space: .everywhere, range: item.topMessage ... (Int32.max - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
for message in result.messages {
|
for message in result.messages {
|
||||||
|
@ -2,6 +2,8 @@ import Foundation
|
|||||||
import TelegramApi
|
import TelegramApi
|
||||||
import Postbox
|
import Postbox
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
import FlatBuffers
|
||||||
|
import FlatSerialization
|
||||||
|
|
||||||
public final class AvailableMessageEffects: Equatable, Codable {
|
public final class AvailableMessageEffects: Equatable, Codable {
|
||||||
public final class MessageEffect: Equatable, Codable {
|
public final class MessageEffect: Equatable, Codable {
|
||||||
@ -10,24 +12,27 @@ public final class AvailableMessageEffects: Equatable, Codable {
|
|||||||
case isPremium
|
case isPremium
|
||||||
case emoticon
|
case emoticon
|
||||||
case staticIcon
|
case staticIcon
|
||||||
|
case staticIconData = "sid"
|
||||||
case effectSticker
|
case effectSticker
|
||||||
|
case effectStickerData = "esd"
|
||||||
case effectAnimation
|
case effectAnimation
|
||||||
|
case effectAnimationData = "ead"
|
||||||
}
|
}
|
||||||
|
|
||||||
public let id: Int64
|
public let id: Int64
|
||||||
public let isPremium: Bool
|
public let isPremium: Bool
|
||||||
public let emoticon: String
|
public let emoticon: String
|
||||||
public let staticIcon: TelegramMediaFile?
|
public let staticIcon: TelegramMediaFile.Accessor?
|
||||||
public let effectSticker: TelegramMediaFile
|
public let effectSticker: TelegramMediaFile.Accessor
|
||||||
public let effectAnimation: TelegramMediaFile?
|
public let effectAnimation: TelegramMediaFile.Accessor?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
id: Int64,
|
id: Int64,
|
||||||
isPremium: Bool,
|
isPremium: Bool,
|
||||||
emoticon: String,
|
emoticon: String,
|
||||||
staticIcon: TelegramMediaFile?,
|
staticIcon: TelegramMediaFile.Accessor?,
|
||||||
effectSticker: TelegramMediaFile,
|
effectSticker: TelegramMediaFile.Accessor,
|
||||||
effectAnimation: TelegramMediaFile?
|
effectAnimation: TelegramMediaFile.Accessor?
|
||||||
) {
|
) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.isPremium = isPremium
|
self.isPremium = isPremium
|
||||||
@ -66,19 +71,28 @@ public final class AvailableMessageEffects: Equatable, Codable {
|
|||||||
self.isPremium = try container.decodeIfPresent(Bool.self, forKey: .isPremium) ?? false
|
self.isPremium = try container.decodeIfPresent(Bool.self, forKey: .isPremium) ?? false
|
||||||
self.emoticon = try container.decode(String.self, forKey: .emoticon)
|
self.emoticon = try container.decode(String.self, forKey: .emoticon)
|
||||||
|
|
||||||
if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) {
|
if let staticIconData = try container.decodeIfPresent(Data.self, forKey: .staticIconData) {
|
||||||
self.staticIcon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data)))
|
var byteBuffer = ByteBuffer(data: staticIconData)
|
||||||
|
self.staticIcon = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, staticIconData)
|
||||||
|
} else if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) {
|
||||||
|
self.staticIcon = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data))))
|
||||||
} else {
|
} else {
|
||||||
self.staticIcon = nil
|
self.staticIcon = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
if let effectStickerData = try container.decodeIfPresent(Data.self, forKey: .effectStickerData) {
|
||||||
|
var byteBuffer = ByteBuffer(data: effectStickerData)
|
||||||
|
self.effectSticker = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectStickerData)
|
||||||
|
} else {
|
||||||
let effectStickerData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectSticker)
|
let effectStickerData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectSticker)
|
||||||
self.effectSticker = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectStickerData.data)))
|
self.effectSticker = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectStickerData.data))))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let effectAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation) {
|
if let effectAnimationData = try container.decodeIfPresent(Data.self, forKey: .effectAnimationData) {
|
||||||
self.effectAnimation = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data)))
|
var byteBuffer = ByteBuffer(data: effectAnimationData)
|
||||||
|
self.effectAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectAnimationData)
|
||||||
|
} else if let effectAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation) {
|
||||||
|
self.effectAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data))))
|
||||||
} else {
|
} else {
|
||||||
self.effectAnimation = nil
|
self.effectAnimation = nil
|
||||||
}
|
}
|
||||||
@ -91,12 +105,26 @@ public final class AvailableMessageEffects: Equatable, Codable {
|
|||||||
try container.encode(self.emoticon, forKey: .emoticon)
|
try container.encode(self.emoticon, forKey: .emoticon)
|
||||||
try container.encode(self.isPremium, forKey: .isPremium)
|
try container.encode(self.isPremium, forKey: .isPremium)
|
||||||
|
|
||||||
if let staticIcon = self.staticIcon {
|
let encodeFileItem: (TelegramMediaFile.Accessor, CodingKeys) throws -> Void = { file, key in
|
||||||
try container.encode(PostboxEncoder().encodeObjectToRawData(staticIcon), forKey: .staticIcon)
|
if let serializedFile = file._wrappedData {
|
||||||
|
try container.encode(serializedFile, forKey: key)
|
||||||
|
} else if let file = file._wrappedFile {
|
||||||
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
|
let value = file.encodeToFlatBuffers(builder: &builder)
|
||||||
|
builder.finish(offset: value)
|
||||||
|
let serializedFile = builder.data
|
||||||
|
try container.encode(serializedFile, forKey: key)
|
||||||
|
} else {
|
||||||
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
try container.encode(PostboxEncoder().encodeObjectToRawData(self.effectSticker), forKey: .effectSticker)
|
}
|
||||||
|
|
||||||
|
if let staticIcon = self.staticIcon {
|
||||||
|
try encodeFileItem(staticIcon, .staticIconData)
|
||||||
|
}
|
||||||
|
try encodeFileItem(self.effectSticker, .effectStickerData)
|
||||||
if let effectAnimation = self.effectAnimation {
|
if let effectAnimation = self.effectAnimation {
|
||||||
try container.encode(PostboxEncoder().encodeObjectToRawData(effectAnimation), forKey: .effectAnimation)
|
try encodeFileItem(effectAnimation, .effectAnimationData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,8 +170,6 @@ public final class AvailableMessageEffects: Equatable, Codable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//availableEffect flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;
|
|
||||||
|
|
||||||
private extension AvailableMessageEffects.MessageEffect {
|
private extension AvailableMessageEffects.MessageEffect {
|
||||||
convenience init?(apiMessageEffect: Api.AvailableEffect, files: [Int64: TelegramMediaFile]) {
|
convenience init?(apiMessageEffect: Api.AvailableEffect, files: [Int64: TelegramMediaFile]) {
|
||||||
switch apiMessageEffect {
|
switch apiMessageEffect {
|
||||||
@ -157,9 +183,9 @@ private extension AvailableMessageEffects.MessageEffect {
|
|||||||
id: id,
|
id: id,
|
||||||
isPremium: isPremium,
|
isPremium: isPremium,
|
||||||
emoticon: emoticon,
|
emoticon: emoticon,
|
||||||
staticIcon: staticIconId.flatMap({ files[$0] }),
|
staticIcon: staticIconId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) }),
|
||||||
effectSticker: effectSticker,
|
effectSticker: TelegramMediaFile.Accessor(effectSticker),
|
||||||
effectAnimation: effectAnimationId.flatMap({ files[$0] })
|
effectAnimation: effectAnimationId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,22 +315,3 @@ func managedSynchronizeAvailableMessageEffects(postbox: Postbox, network: Networ
|
|||||||
)
|
)
|
||||||
|> restart
|
|> restart
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension Message {
|
|
||||||
func messageEffect(availableMessageEffects: AvailableMessageEffects?) -> AvailableMessageEffects.MessageEffect? {
|
|
||||||
guard let availableMessageEffects else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for attribute in self.attributes {
|
|
||||||
if let attribute = attribute as? EffectMessageAttribute {
|
|
||||||
for effect in availableMessageEffects.messageEffects {
|
|
||||||
if effect.id == attribute.id {
|
|
||||||
return effect
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1411,7 +1411,7 @@ public final class InstantPage: PostboxCoding, Equatable {
|
|||||||
self.url = decoder.decodeStringForKey("url", orElse: "")
|
self.url = decoder.decodeStringForKey("url", orElse: "")
|
||||||
self.views = decoder.decodeOptionalInt32ForKey("v")
|
self.views = decoder.decodeOptionalInt32ForKey("v")
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG && false
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
let offset = self.encodeToFlatBuffers(builder: &builder)
|
let offset = self.encodeToFlatBuffers(builder: &builder)
|
||||||
builder.finish(offset: offset)
|
builder.finish(offset: offset)
|
||||||
|
@ -104,7 +104,7 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable {
|
|||||||
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
|
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
|
||||||
encoder.encodeInt32(self.count, forKey: "n")
|
encoder.encodeInt32(self.count, forKey: "n")
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG && false
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
let offset = self.encodeToFlatBuffers(builder: &builder)
|
let offset = self.encodeToFlatBuffers(builder: &builder)
|
||||||
builder.finish(offset: offset)
|
builder.finish(offset: offset)
|
||||||
|
@ -347,7 +347,7 @@ public final class TelegramChannel: Peer, Equatable {
|
|||||||
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
|
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
|
||||||
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
|
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG && false
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
let offset = self.encodeToFlatBuffers(builder: &builder)
|
let offset = self.encodeToFlatBuffers(builder: &builder)
|
||||||
builder.finish(offset: offset)
|
builder.finish(offset: offset)
|
||||||
|
@ -207,7 +207,7 @@ public final class TelegramGroup: Peer, Equatable {
|
|||||||
self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0)
|
self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0)
|
||||||
self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0))
|
self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0))
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG && false
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
let offset = self.encodeToFlatBuffers(builder: &builder)
|
let offset = self.encodeToFlatBuffers(builder: &builder)
|
||||||
builder.finish(offset: offset)
|
builder.finish(offset: offset)
|
||||||
|
@ -698,8 +698,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
|||||||
} else if let lhsWrappedData = lhs._wrappedData, let rhsWrappedData = rhs._wrappedData {
|
} else if let lhsWrappedData = lhs._wrappedData, let rhsWrappedData = rhs._wrappedData {
|
||||||
return lhsWrappedData == rhsWrappedData
|
return lhsWrappedData == rhsWrappedData
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
return lhs._parse() == rhs._parse()
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -903,13 +902,6 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
|||||||
try container.encode(postboxEncoder.makeData(), forKey: .data)
|
try container.encode(postboxEncoder.makeData(), forKey: .data)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encodeToFlatBuffersData() -> Data {
|
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
|
||||||
let value = self.encodeToFlatBuffers(builder: &builder)
|
|
||||||
builder.finish(offset: value)
|
|
||||||
return builder.data
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(flatBuffersObject: TelegramCore_TelegramMediaFile) throws {
|
public init(flatBuffersObject: TelegramCore_TelegramMediaFile) throws {
|
||||||
self.fileId = MediaId(namespace: flatBuffersObject.fileId.namespace, id: flatBuffersObject.fileId.id)
|
self.fileId = MediaId(namespace: flatBuffersObject.fileId.namespace, id: flatBuffersObject.fileId.id)
|
||||||
self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0 ) }
|
self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0 ) }
|
||||||
|
@ -21,10 +21,21 @@ private let cloudSoundMapping: [Int32: Int64] = [
|
|||||||
108: 5078299559046677216,
|
108: 5078299559046677216,
|
||||||
109: 5078299559046677217,
|
109: 5078299559046677217,
|
||||||
110: 5078299559046677218,
|
110: 5078299559046677218,
|
||||||
111: 5078299559046677219
|
111: 5078299559046677219,
|
||||||
|
200: 5032932652722685163,
|
||||||
|
201: 5032932652722685160,
|
||||||
|
202: 5032932652722685159,
|
||||||
|
203: 5032932652722685158,
|
||||||
|
204: 5032932652722685168,
|
||||||
|
205: 5032932652722685167,
|
||||||
|
206: 5032932652722685166,
|
||||||
|
207: 5032932652722685165,
|
||||||
|
208: 5032932652722685164,
|
||||||
|
209: 5032932652722685162,
|
||||||
|
210: 5032932652722685161
|
||||||
]
|
]
|
||||||
|
|
||||||
public let defaultCloudPeerNotificationSound: PeerMessageSound = .cloud(fileId: cloudSoundMapping[100]!)
|
public let defaultCloudPeerNotificationSound: PeerMessageSound = .cloud(fileId: cloudSoundMapping[200]!)
|
||||||
|
|
||||||
public enum CloudSoundBuiltinCategory {
|
public enum CloudSoundBuiltinCategory {
|
||||||
case modern
|
case modern
|
||||||
|
@ -331,7 +331,7 @@ public final class TelegramUser: Peer, Equatable {
|
|||||||
self.subscriberCount = decoder.decodeOptionalInt32ForKey("ssc")
|
self.subscriberCount = decoder.decodeOptionalInt32ForKey("ssc")
|
||||||
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
|
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG && false
|
||||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||||
let offset = self.encodeToFlatBuffers(builder: &builder)
|
let offset = self.encodeToFlatBuffers(builder: &builder)
|
||||||
builder.finish(offset: offset)
|
builder.finish(offset: offset)
|
||||||
|
@ -642,3 +642,22 @@ public func _internal_parseMediaAttachment(data: Data) -> Media? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension Message {
|
||||||
|
func messageEffect(availableMessageEffects: AvailableMessageEffects?) -> AvailableMessageEffects.MessageEffect? {
|
||||||
|
guard let availableMessageEffects else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for attribute in self.attributes {
|
||||||
|
if let attribute = attribute as? EffectMessageAttribute {
|
||||||
|
for effect in availableMessageEffects.messageEffects {
|
||||||
|
if effect.id == attribute.id {
|
||||||
|
return effect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -14,7 +14,18 @@ private let modernSoundsNamePaths: [KeyPath<PresentationStrings, String>] = [
|
|||||||
\.NotificationsSound_Keys,
|
\.NotificationsSound_Keys,
|
||||||
\.NotificationsSound_Popcorn,
|
\.NotificationsSound_Popcorn,
|
||||||
\.NotificationsSound_Pulse,
|
\.NotificationsSound_Pulse,
|
||||||
\.NotificationsSound_Synth
|
\.NotificationsSound_Synth,
|
||||||
|
\.NotificationsSound_Rebound,
|
||||||
|
\.NotificationsSound_Antic,
|
||||||
|
\.NotificationsSound_Cheers,
|
||||||
|
\.NotificationsSound_Droplet,
|
||||||
|
\.NotificationsSound_Handoff,
|
||||||
|
\.NotificationsSound_Milestone,
|
||||||
|
\.NotificationsSound_Passage,
|
||||||
|
\.NotificationsSound_Portal,
|
||||||
|
\.NotificationsSound_Rattle,
|
||||||
|
\.NotificationsSound_Slide,
|
||||||
|
\.NotificationsSound_Welcome
|
||||||
]
|
]
|
||||||
|
|
||||||
private let classicSoundNamePaths: [KeyPath<PresentationStrings, String>] = [
|
private let classicSoundNamePaths: [KeyPath<PresentationStrings, String>] = [
|
||||||
|
@ -1116,7 +1116,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
|||||||
|
|
||||||
var centerAnimation: TelegramMediaFile?
|
var centerAnimation: TelegramMediaFile?
|
||||||
|
|
||||||
centerAnimation = messageEffect.staticIcon
|
centerAnimation = messageEffect.staticIcon?._parse()
|
||||||
|
|
||||||
node.update(
|
node.update(
|
||||||
context: arguments.context,
|
context: arguments.context,
|
||||||
|
@ -2286,7 +2286,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
|
|
||||||
if automaticDownload != .none, let file = media as? TelegramMediaFile, NativeVideoContent.isHLSVideo(file: file) {
|
if automaticDownload != .none, let file = media as? TelegramMediaFile, NativeVideoContent.isHLSVideo(file: file) {
|
||||||
let postbox = context.account.postbox
|
let postbox = context.account.postbox
|
||||||
let fetchSignal = HLSVideoContent.minimizedHLSQualityPreloadData(postbox: context.account.postbox, file: .message(message: MessageReference(message), media: file), userLocation: .peer(message.id.peerId), prefixSeconds: 10, autofetchPlaylist: true, codecConfiguration: HLSCodecConfiguration(context: context))
|
let fetchSignal: Signal<Never, NoError>
|
||||||
|
fetchSignal = HLSVideoContent.minimizedHLSQualityPreloadData(postbox: context.account.postbox, file: .message(message: MessageReference(message), media: file), userLocation: .peer(message.id.peerId), prefixSeconds: 10, autofetchPlaylist: true, codecConfiguration: HLSCodecConfiguration(context: context))
|
||||||
|> mapToSignal { fileAndRange -> Signal<Never, NoError> in
|
|> mapToSignal { fileAndRange -> Signal<Never, NoError> in
|
||||||
guard let fileAndRange else {
|
guard let fileAndRange else {
|
||||||
return .complete()
|
return .complete()
|
||||||
|
@ -938,13 +938,13 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol {
|
|||||||
}
|
}
|
||||||
self.playedEffectAnimation = true
|
self.playedEffectAnimation = true
|
||||||
|
|
||||||
if let effectAnimation = effect.effectAnimation {
|
if let effectAnimation = effect.effectAnimation?._parse() {
|
||||||
self.playEffectAnimation(resource: effectAnimation.resource)
|
self.playEffectAnimation(resource: effectAnimation.resource)
|
||||||
if self.fetchEffectDisposable == nil {
|
if self.fetchEffectDisposable == nil {
|
||||||
self.fetchEffectDisposable = freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .other, fileReference: .standalone(media: effectAnimation), resource: effectAnimation.resource).startStrict()
|
self.fetchEffectDisposable = freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .other, fileReference: .standalone(media: effectAnimation), resource: effectAnimation.resource).startStrict()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let effectSticker = effect.effectSticker
|
let effectSticker = effect.effectSticker._parse()
|
||||||
if let effectFile = effectSticker.videoThumbnails.first {
|
if let effectFile = effectSticker.videoThumbnails.first {
|
||||||
self.playEffectAnimation(resource: effectFile.resource)
|
self.playEffectAnimation(resource: effectFile.resource)
|
||||||
if self.fetchEffectDisposable == nil {
|
if self.fetchEffectDisposable == nil {
|
||||||
|
@ -501,7 +501,7 @@ public func effectMessageReactions(context: AccountContext) -> Signal<[ReactionI
|
|||||||
}
|
}
|
||||||
existingIds.insert(messageEffect.id)
|
existingIds.insert(messageEffect.id)
|
||||||
|
|
||||||
let mainFile = TelegramMediaFile.Accessor(messageEffect.effectSticker)
|
let mainFile = messageEffect.effectSticker
|
||||||
|
|
||||||
result.append(ReactionItem(
|
result.append(ReactionItem(
|
||||||
reaction: ReactionItem.Reaction(rawValue: .custom(messageEffect.id)),
|
reaction: ReactionItem.Reaction(rawValue: .custom(messageEffect.id)),
|
||||||
|
@ -82,18 +82,20 @@ public func generateTopicIcon(title: String, backgroundColors: [UIColor], stroke
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum AnimationCacheAnimationType {
|
public enum AnimationCacheAnimationType: Equatable {
|
||||||
case still
|
case still
|
||||||
case lottie
|
case lottie
|
||||||
case video
|
case video(isVP9: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension AnimationCacheAnimationType {
|
public extension AnimationCacheAnimationType {
|
||||||
init(file: TelegramMediaFile) {
|
init(file: TelegramMediaFile) {
|
||||||
if file.isVideoSticker || file.isVideoEmoji {
|
if file.isVideoSticker || file.isVideoEmoji {
|
||||||
self = .video
|
self = .video(isVP9: true)
|
||||||
} else if file.isAnimatedSticker {
|
} else if file.isAnimatedSticker {
|
||||||
self = .lottie
|
self = .lottie
|
||||||
|
} else if file.isVideo {
|
||||||
|
self = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
self = .still
|
self = .still
|
||||||
}
|
}
|
||||||
@ -122,8 +124,8 @@ public func animationCacheFetchFile(postbox: Postbox, userLocation: MediaResourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .video:
|
case let .video(isVP9):
|
||||||
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
cacheVideoAnimation(path: result, hintVP9: isVP9, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
||||||
case .lottie:
|
case .lottie:
|
||||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
|
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
|
||||||
options.writer.finish()
|
options.writer.finish()
|
||||||
@ -153,8 +155,8 @@ public func animationCacheLoadLocalFile(name: String, type: AnimationCacheAnimat
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch type {
|
switch type {
|
||||||
case .video:
|
case let .video(isVP9):
|
||||||
cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
cacheVideoAnimation(path: result, hintVP9: isVP9, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor)
|
||||||
case .lottie:
|
case .lottie:
|
||||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
|
guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else {
|
||||||
options.writer.finish()
|
options.writer.finish()
|
||||||
|
@ -33,7 +33,7 @@ public final class EmojiKeyboardItemLayer: MultiAnimationRenderTarget {
|
|||||||
case locked
|
case locked
|
||||||
case featured
|
case featured
|
||||||
case text(String)
|
case text(String)
|
||||||
case customFile(TelegramMediaFile)
|
case customFile(TelegramMediaFile.Accessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
public let item: EmojiPagerContentComponent.Item
|
public let item: EmojiPagerContentComponent.Item
|
||||||
|
@ -43,10 +43,10 @@ public final class EntityKeyboardAnimationData: Equatable {
|
|||||||
case gift(String)
|
case gift(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ItemType {
|
public enum ItemType: Equatable {
|
||||||
case still
|
case still
|
||||||
case lottie
|
case lottie
|
||||||
case video
|
case video(isVP9: Bool)
|
||||||
|
|
||||||
var animationCacheAnimationType: AnimationCacheAnimationType {
|
var animationCacheAnimationType: AnimationCacheAnimationType {
|
||||||
switch self {
|
switch self {
|
||||||
@ -54,8 +54,8 @@ public final class EntityKeyboardAnimationData: Equatable {
|
|||||||
return .still
|
return .still
|
||||||
case .lottie:
|
case .lottie:
|
||||||
return .lottie
|
return .lottie
|
||||||
case .video:
|
case let .video(isVP9):
|
||||||
return .video
|
return .video(isVP9: isVP9)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,9 +105,11 @@ public final class EntityKeyboardAnimationData: Equatable {
|
|||||||
public convenience init(file: TelegramMediaFile.Accessor, isReaction: Bool = false, partialReference: PartialMediaReference? = nil) {
|
public convenience init(file: TelegramMediaFile.Accessor, isReaction: Bool = false, partialReference: PartialMediaReference? = nil) {
|
||||||
let type: ItemType
|
let type: ItemType
|
||||||
if file.isVideoSticker || file.isVideoEmoji {
|
if file.isVideoSticker || file.isVideoEmoji {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
} else if file.isAnimatedSticker {
|
} else if file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
|
} else if file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -406,7 +408,7 @@ public final class EmojiPagerContentComponent: Component {
|
|||||||
case locked
|
case locked
|
||||||
case premium
|
case premium
|
||||||
case text(String)
|
case text(String)
|
||||||
case customFile(TelegramMediaFile)
|
case customFile(TelegramMediaFile.Accessor)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TintMode: Equatable {
|
public enum TintMode: Equatable {
|
||||||
|
@ -287,7 +287,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -1390,7 +1392,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -1477,7 +1481,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -1774,7 +1780,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -2011,7 +2019,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -2090,7 +2100,9 @@ public extension EmojiPagerContentComponent {
|
|||||||
if item.file.isAnimatedSticker {
|
if item.file.isAnimatedSticker {
|
||||||
type = .lottie
|
type = .lottie
|
||||||
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
} else if item.file.isVideoEmoji || item.file.isVideoSticker {
|
||||||
type = .video
|
type = .video(isVP9: true)
|
||||||
|
} else if item.file.isVideo {
|
||||||
|
type = .video(isVP9: false)
|
||||||
} else {
|
} else {
|
||||||
type = .still
|
type = .still
|
||||||
}
|
}
|
||||||
@ -2234,7 +2246,7 @@ public extension EmojiPagerContentComponent {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemFile: TelegramMediaFile = item.effectSticker
|
let itemFile = item.effectSticker
|
||||||
|
|
||||||
var tintMode: Item.TintMode = .none
|
var tintMode: Item.TintMode = .none
|
||||||
if itemFile.isCustomTemplateEmoji {
|
if itemFile.isCustomTemplateEmoji {
|
||||||
@ -2258,11 +2270,11 @@ public extension EmojiPagerContentComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let animationData = EntityKeyboardAnimationData(file: TelegramMediaFile.Accessor(itemFile), partialReference: .none)
|
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
|
||||||
let resultItem = EmojiPagerContentComponent.Item(
|
let resultItem = EmojiPagerContentComponent.Item(
|
||||||
animationData: animationData,
|
animationData: animationData,
|
||||||
content: .animation(animationData),
|
content: .animation(animationData),
|
||||||
itemFile: TelegramMediaFile.Accessor(itemFile),
|
itemFile: itemFile,
|
||||||
subgroupId: nil,
|
subgroupId: nil,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
tintMode: tintMode
|
tintMode: tintMode
|
||||||
|
@ -81,7 +81,7 @@ final class PremiumBadgeView: UIView {
|
|||||||
context: self.context,
|
context: self.context,
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
attemptSynchronousLoad: false,
|
attemptSynchronousLoad: false,
|
||||||
file: customFile,
|
file: customFile._parse(),
|
||||||
cache: self.context.animationCache,
|
cache: self.context.animationCache,
|
||||||
renderer: self.context.animationRenderer,
|
renderer: self.context.animationRenderer,
|
||||||
unique: false,
|
unique: false,
|
||||||
|
@ -18,9 +18,9 @@ private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
|
|||||||
return numToRound + multiple - remainder
|
return numToRound + multiple - remainder
|
||||||
}
|
}
|
||||||
|
|
||||||
public func cacheVideoAnimation(path: String, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
|
public func cacheVideoAnimation(path: String, hintVP9: Bool, width: Int, height: Int, writer: AnimationCacheItemWriter, firstFrameOnly: Bool, customColor: UIColor?) {
|
||||||
let work: () -> Void = {
|
let work: () -> Void = {
|
||||||
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
|
guard let frameSource = makeVideoStickerDirectFrameSource(queue: writer.queue, path: path, hintVP9: hintVP9, width: roundUp(width, multiple: 16), height: roundUp(height, multiple: 16), cachePathPrefix: nil, unpremultiplyAlpha: false) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let frameDuration = 1.0 / Double(frameSource.frameRate)
|
let frameDuration = 1.0 / Double(frameSource.frameRate)
|
||||||
|
@ -102,7 +102,7 @@ private final class EffectBadgeView: UIView {
|
|||||||
}
|
}
|
||||||
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
|
let effectIconContent: ChatSendMessageScreenEffectIcon.Content
|
||||||
if let staticIcon = effect.staticIcon {
|
if let staticIcon = effect.staticIcon {
|
||||||
effectIconContent = .file(staticIcon)
|
effectIconContent = .file(staticIcon._parse())
|
||||||
} else {
|
} else {
|
||||||
effectIconContent = .text(effect.emoticon)
|
effectIconContent = .text(effect.emoticon)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user