diff --git a/Telegram/Telegram-iOS/Resources/notifications/0.m4a b/Telegram/Telegram-iOS/Resources/notifications/0.m4a index e3f9bdcb2a..f8026837be 100644 Binary files a/Telegram/Telegram-iOS/Resources/notifications/0.m4a and b/Telegram/Telegram-iOS/Resources/notifications/0.m4a differ diff --git a/submodules/AnimatedStickerNode/Sources/DirectAnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/DirectAnimatedStickerNode.swift index 49eac5f5b5..eea15a90c1 100644 --- a/submodules/AnimatedStickerNode/Sources/DirectAnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/DirectAnimatedStickerNode.swift @@ -112,7 +112,7 @@ public final class DirectAnimatedStickerNode: ASDisplayNode, AnimatedStickerNode } 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) } } else { diff --git a/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift b/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift index fba3e52733..120ad0e2e9 100644 --- a/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift +++ b/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift @@ -273,8 +273,8 @@ private final class VideoStickerFrameSourceCache { private let useCache = true -public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? { - return VideoStickerDirectFrameSource(queue: queue, path: path, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha) +public func makeVideoStickerDirectFrameSource(queue: Queue, path: String, hintVP9: Bool, width: Int, height: Int, cachePathPrefix: String?, unpremultiplyAlpha: Bool) -> AnimatedStickerFrameSource? { + return VideoStickerDirectFrameSource(queue: queue, path: path, isVP9: hintVP9, width: width, height: height, cachePathPrefix: cachePathPrefix, unpremultiplyAlpha: unpremultiplyAlpha) } public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource { @@ -290,7 +290,7 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource { public var duration: Double fileprivate var currentFrame: Int - private let source: SoftwareVideoSource? + private var source: FFMpegFileReader? public var frameIndex: Int { 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.path = path self.width = width @@ -329,12 +329,25 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource { self.frameCount = 1 self.duration = 0.0 } else { - let source = SoftwareVideoSource(path: path, hintVP9: true, unpremultiplyAlpha: unpremultiplyAlpha) - self.source = source + let source = FFMpegFileReader( + source: .file(path), + passthroughDecoder: false, + useHardwareAcceleration: false, + selectedStream: .mediaType(.video), + seek: nil, + maxReadablePts: nil + ) + if let 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.frameRate = min(30, source.getFramerate()) self.frameCount = 0 - self.duration = source.reportedDuration.seconds } } @@ -365,56 +378,66 @@ public final class VideoStickerDirectFrameSource: AnimatedStickerFrameSource { } 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) } else if let source = self.source { - let frameAndLoop = source.readFrame(maxPts: nil) - if frameAndLoop.0 == nil { - if frameAndLoop.3 { - 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 - } + let frameAndLoop = source.readFrame(argb: true) + switch frameAndLoop { + case let .frame(frame): + var frameData = Data(count: self.bytesPerRow * self.height) + frameData.withUnsafeMutableBytes { buffer -> Void in + guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { + return } - self.currentFrame = 0 - } else { - Logger.shared.log("VideoSticker", "Skipped a frame?") + + let imageBuffer = CMSampleBufferGetImageBuffer(frame.sampleBuffer) + CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) + let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!) + let width = CVPixelBufferGetWidth(imageBuffer!) + let height = CVPixelBufferGetHeight(imageBuffer!) + let srcData = CVPixelBufferGetBaseAddress(imageBuffer!) + + var sourceBuffer = vImage_Buffer(data: srcData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) + var destBuffer = vImage_Buffer(data: bytes, height: vImagePixelCount(self.height), width: vImagePixelCount(self.width), rowBytes: self.bytesPerRow) + + let _ = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageDoNotTile)) + + CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) } - return nil - } - - guard let frame = frameAndLoop.0 else { - return nil - } - - var frameData = Data(count: self.bytesPerRow * self.height) - frameData.withUnsafeMutableBytes { buffer -> Void in - guard let bytes = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { - return - } - - let imageBuffer = CMSampleBufferGetImageBuffer(frame.sampleBuffer) - CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) - let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!) - let width = CVPixelBufferGetWidth(imageBuffer!) - let height = CVPixelBufferGetHeight(imageBuffer!) - let srcData = CVPixelBufferGetBaseAddress(imageBuffer!) - - var sourceBuffer = vImage_Buffer(data: srcData, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) - var destBuffer = vImage_Buffer(data: bytes, height: vImagePixelCount(self.height), width: vImagePixelCount(self.width), rowBytes: self.bytesPerRow) - - let _ = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageDoNotTile)) - - CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0)) - } - 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) + 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) + 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 { return nil } diff --git a/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift b/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift index 9cdfac6a64..bb787e1836 100644 --- a/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift +++ b/submodules/AvatarVideoNode/Sources/AvatarVideoNode.swift @@ -25,6 +25,7 @@ public final class AvatarVideoNode: ASDisplayNode { private var emojiMarkup: TelegramMediaImage.EmojiMarkup? + private var videoFileDisposable: Disposable? private var fileDisposable = MetaDisposable() private var animationFile: TelegramMediaFile? private var itemLayer: EmojiKeyboardItemLayer? @@ -32,6 +33,7 @@ public final class AvatarVideoNode: ASDisplayNode { private var animationNode: AnimatedStickerNode? private let stickerFetchedDisposable = MetaDisposable() + private var videoItemLayer: EmojiKeyboardItemLayer? private var videoNode: UniversalVideoNode? private var videoContent: NativeVideoContent? private let playbackStartDisposable = MetaDisposable() @@ -55,6 +57,7 @@ public final class AvatarVideoNode: ASDisplayNode { } deinit { + self.videoFileDisposable?.dispose() self.fileDisposable.dispose() self.stickerFetchedDisposable.dispose() self.playbackStartDisposable.dispose() @@ -137,6 +140,7 @@ public final class AvatarVideoNode: ASDisplayNode { self.videoLoopCount += 1 if self.videoLoopCount >= maxVideoLoopCount { self.itemLayer?.isVisibleForAnimations = false + self.videoItemLayer?.isVisibleForAnimations = false } } } @@ -211,6 +215,9 @@ public final class AvatarVideoNode: ASDisplayNode { if videoContent.id != self.videoContent?.id { self.videoNode?.removeFromSupernode() 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,56 +238,111 @@ public final class AvatarVideoNode: ASDisplayNode { } self.animationNode?.visibility = isVisible if isVisible, let videoContent = self.videoContent, self.videoLoopCount < maxVideoLoopCount { - if self.videoNode == nil { - let context = self.context - let mediaManager = context.sharedContext.mediaManager - let videoNode = UniversalVideoNode(context: context, postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: VideoDecoration(), content: videoContent, priority: .embedded) - videoNode.clipsToBounds = true - videoNode.isUserInteractionEnabled = false - videoNode.isHidden = true - videoNode.playbackCompleted = { [weak self] in - if let strongSelf = self { - strongSelf.videoLoopCount += 1 - if strongSelf.videoLoopCount >= maxVideoLoopCount { - if let videoNode = strongSelf.videoNode { - strongSelf.videoNode = nil - videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in - videoNode?.removeFromSupernode() - }) + 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) } - - if let _ = videoContent.startTimestamp { - self.playbackStartDisposable.set((videoNode.status - |> map { status -> Bool in - if let status = status, case .playing = status.status { - return true - } else { - return false - } - } - |> filter { playing in - return playing - } - |> take(1) - |> deliverOnMainQueue).startStrict(completed: { [weak self] in + } 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 { + let context = self.context + let mediaManager = context.sharedContext.mediaManager + let videoNode = UniversalVideoNode(context: context, postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: VideoDecoration(), content: videoContent, priority: .embedded) + videoNode.clipsToBounds = true + videoNode.isUserInteractionEnabled = false + videoNode.isHidden = true + videoNode.playbackCompleted = { [weak self] in if let strongSelf = self { - Queue.mainQueue().after(0.15) { - strongSelf.videoNode?.isHidden = false + strongSelf.videoLoopCount += 1 + if strongSelf.videoLoopCount >= maxVideoLoopCount { + if let videoNode = strongSelf.videoNode { + strongSelf.videoNode = nil + videoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak videoNode] _ in + videoNode?.removeFromSupernode() + }) + } } } - })) - } else { - self.playbackStartDisposable.set(nil) - videoNode.isHidden = false + } + + if let _ = videoContent.startTimestamp { + self.playbackStartDisposable.set((videoNode.status + |> map { status -> Bool in + if let status = status, case .playing = status.status { + return true + } else { + return false + } + } + |> filter { playing in + return playing + } + |> take(1) + |> deliverOnMainQueue).startStrict(completed: { [weak self] in + if let strongSelf = self { + Queue.mainQueue().after(0.15) { + strongSelf.videoNode?.isHidden = false + } + } + })) + } else { + self.playbackStartDisposable.set(nil) + videoNode.isHidden = false + } + videoNode.canAttachContent = true + videoNode.play() + + self.addSubnode(videoNode) + self.videoNode = videoNode } - videoNode.canAttachContent = true - videoNode.play() - - self.addSubnode(videoNode) - self.videoNode = videoNode } } else if let videoNode = self.videoNode { self.videoNode = nil @@ -289,6 +351,7 @@ public final class AvatarVideoNode: ASDisplayNode { if self.videoLoopCount < maxVideoLoopCount { self.itemLayer?.isVisibleForAnimations = isVisible } + self.videoItemLayer?.isVisibleForAnimations = isVisible } 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.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 itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - itemSize.width) / 2.0), y: floorToScreenPixels((size.height - itemSize.height) / 2.0)), size: itemSize) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 3c2c57a158..86d3f3b783 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -1747,7 +1747,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { self.avatarNode.font = avatarPlaceholderFont(size: avatarFontSize) } } - 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.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)) + } if peer.isPremium && peer.id != item.context.account.peerId { let context = item.context diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift index 93e5152744..f329936da6 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageContextScreen.swift @@ -954,10 +954,10 @@ final class ChatSendMessageContextScreenComponent: Component { } var customEffectResource: (FileMediaReference, MediaResource)? - if let effectAnimation = messageEffect.effectAnimation { + if let effectAnimation = messageEffect.effectAnimation?._parse() { customEffectResource = (FileMediaReference.standalone(media: effectAnimation), effectAnimation.resource) } else { - let effectSticker = messageEffect.effectSticker + let effectSticker = messageEffect.effectSticker._parse() if let effectFile = effectSticker.videoThumbnails.first { customEffectResource = (FileMediaReference.standalone(media: effectSticker), effectFile.resource) } diff --git a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift index 3fddcea629..0dee40ddfd 100644 --- a/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift +++ b/submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift @@ -309,7 +309,7 @@ final class MessageItemView: UIView { } let effectIconContent: ChatSendMessageScreenEffectIcon.Content if let staticIcon = effect.staticIcon { - effectIconContent = .file(staticIcon) + effectIconContent = .file(staticIcon._parse()) } else { effectIconContent = .text(effect.emoticon) } diff --git a/submodules/Display/Source/NavigationTransitionCoordinator.swift b/submodules/Display/Source/NavigationTransitionCoordinator.swift index 89152cc22b..3643832216 100644 --- a/submodules/Display/Source/NavigationTransitionCoordinator.swift +++ b/submodules/Display/Source/NavigationTransitionCoordinator.swift @@ -52,6 +52,8 @@ final class NavigationTransitionCoordinator { private var currentCompletion: (() -> 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) { self.transition = transition self.isInteractive = isInteractive @@ -114,6 +116,8 @@ final class NavigationTransitionCoordinator { self.maybeCreateNavigationBarTransition() self.updateProgress(0.0, transition: .immediate, completion: {}) + + self.frameRateLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { _ in }) } required init(coder aDecoder: NSCoder) { diff --git a/submodules/MediaPlayer/Sources/FFMpegFileReader.swift b/submodules/MediaPlayer/Sources/FFMpegFileReader.swift index 7bb1b7d2d6..804279808b 100644 --- a/submodules/MediaPlayer/Sources/FFMpegFileReader.swift +++ b/submodules/MediaPlayer/Sources/FFMpegFileReader.swift @@ -403,6 +403,22 @@ public final class FFMpegFileReader { 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? { guard let avFormatContext = self.avFormatContext else { return nil @@ -452,7 +468,7 @@ public final class FFMpegFileReader { return nil } - public func readFrame() -> ReadFrameResult { + public func readFrame(argb: Bool = false) -> ReadFrameResult { guard let stream = self.stream else { return .error } @@ -461,7 +477,7 @@ public final class FFMpegFileReader { var result: MediaTrackFrame? switch stream.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): result = decoder.decode() case let .audio(decoder): diff --git a/submodules/PhotoResources/Sources/PhotoResources.swift b/submodules/PhotoResources/Sources/PhotoResources.swift index 46a8a8e5a8..b6c3d06e48 100644 --- a/submodules/PhotoResources/Sources/PhotoResources.swift +++ b/submodules/PhotoResources/Sources/PhotoResources.swift @@ -448,7 +448,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, userLocation: 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?, Bool>, NoError> { +private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, alternativeFileAndRange: Signal<(TelegramMediaFile, Range), NoError>? = nil, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal?, Bool>, NoError> { let fullSizeResource = fileReference.media.resource var reducedSizeResource: MediaResource? 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), 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?, Bool>, NoError> if let imageReference = imageReference { 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) } } 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 diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index bc4608d87b..e04b1c2a89 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -1893,7 +1893,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate { for i in 0 ..< 2 { let groupId = i == 0 ? "reactions" : "stickers" for item in i == 0 ? reactionEffects : stickerEffects { - let itemFile: TelegramMediaFile = item.effectSticker + let itemFile = item.effectSticker var tintMode: EmojiPagerContentComponent.Item.TintMode = .none 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( animationData: animationData, content: .animation(animationData), - itemFile: TelegramMediaFile.Accessor(itemFile), + itemFile: itemFile, subgroupId: nil, icon: icon, tintMode: tintMode @@ -2257,7 +2257,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate { for i in 0 ..< 2 { let groupId = i == 0 ? "reactions" : "stickers" for item in i == 0 ? reactionEffects : stickerEffects { - let itemFile: TelegramMediaFile = item.effectSticker + let itemFile = item.effectSticker var tintMode: EmojiPagerContentComponent.Item.TintMode = .none 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( animationData: animationData, content: .animation(animationData), - itemFile: TelegramMediaFile.Accessor(itemFile), + itemFile: itemFile, subgroupId: nil, icon: icon, tintMode: tintMode diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index 52ba6b348c..8b8a9fccce 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -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) 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 { diff --git a/submodules/TelegramCore/Sources/State/AvailableMessageEffects.swift b/submodules/TelegramCore/Sources/State/AvailableMessageEffects.swift index 8070509f5e..f5bf7e5baa 100644 --- a/submodules/TelegramCore/Sources/State/AvailableMessageEffects.swift +++ b/submodules/TelegramCore/Sources/State/AvailableMessageEffects.swift @@ -2,6 +2,8 @@ import Foundation import TelegramApi import Postbox import SwiftSignalKit +import FlatBuffers +import FlatSerialization public final class AvailableMessageEffects: Equatable, Codable { public final class MessageEffect: Equatable, Codable { @@ -10,24 +12,27 @@ public final class AvailableMessageEffects: Equatable, Codable { case isPremium case emoticon case staticIcon + case staticIconData = "sid" case effectSticker + case effectStickerData = "esd" case effectAnimation + case effectAnimationData = "ead" } public let id: Int64 public let isPremium: Bool public let emoticon: String - public let staticIcon: TelegramMediaFile? - public let effectSticker: TelegramMediaFile - public let effectAnimation: TelegramMediaFile? + public let staticIcon: TelegramMediaFile.Accessor? + public let effectSticker: TelegramMediaFile.Accessor + public let effectAnimation: TelegramMediaFile.Accessor? public init( id: Int64, isPremium: Bool, emoticon: String, - staticIcon: TelegramMediaFile?, - effectSticker: TelegramMediaFile, - effectAnimation: TelegramMediaFile? + staticIcon: TelegramMediaFile.Accessor?, + effectSticker: TelegramMediaFile.Accessor, + effectAnimation: TelegramMediaFile.Accessor? ) { self.id = id self.isPremium = isPremium @@ -66,19 +71,28 @@ public final class AvailableMessageEffects: Equatable, Codable { self.isPremium = try container.decodeIfPresent(Bool.self, forKey: .isPremium) ?? false self.emoticon = try container.decode(String.self, forKey: .emoticon) - if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) { - self.staticIcon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data))) + if let staticIconData = try container.decodeIfPresent(Data.self, forKey: .staticIconData) { + 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 { 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) - 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) { - self.effectAnimation = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data))) + if let effectAnimationData = try container.decodeIfPresent(Data.self, forKey: .effectAnimationData) { + 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 { self.effectAnimation = nil } @@ -91,12 +105,26 @@ public final class AvailableMessageEffects: Equatable, Codable { try container.encode(self.emoticon, forKey: .emoticon) try container.encode(self.isPremium, forKey: .isPremium) - if let staticIcon = self.staticIcon { - try container.encode(PostboxEncoder().encodeObjectToRawData(staticIcon), forKey: .staticIcon) + let encodeFileItem: (TelegramMediaFile.Accessor, CodingKeys) throws -> Void = { file, key in + 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 { - 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 { convenience init?(apiMessageEffect: Api.AvailableEffect, files: [Int64: TelegramMediaFile]) { switch apiMessageEffect { @@ -157,9 +183,9 @@ private extension AvailableMessageEffects.MessageEffect { id: id, isPremium: isPremium, emoticon: emoticon, - staticIcon: staticIconId.flatMap({ files[$0] }), - effectSticker: effectSticker, - effectAnimation: effectAnimationId.flatMap({ files[$0] }) + staticIcon: staticIconId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) }), + effectSticker: TelegramMediaFile.Accessor(effectSticker), + effectAnimation: effectAnimationId.flatMap({ files[$0].flatMap(TelegramMediaFile.Accessor.init) }) ) } } @@ -289,22 +315,3 @@ func managedSynchronizeAvailableMessageEffects(postbox: Postbox, network: Networ ) |> 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 - } -} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift index 24288a45ba..b00622915e 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_InstantPage.swift @@ -1411,7 +1411,7 @@ public final class InstantPage: PostboxCoding, Equatable { self.url = decoder.decodeStringForKey("url", orElse: "") self.views = decoder.decodeOptionalInt32ForKey("v") - #if DEBUG + #if DEBUG && false var builder = FlatBufferBuilder(initialSize: 1024) let offset = self.encodeToFlatBuffers(builder: &builder) builder.finish(offset: offset) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackCollectionInfo.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackCollectionInfo.swift index 1af0e79bda..682296a622 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackCollectionInfo.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackCollectionInfo.swift @@ -104,7 +104,7 @@ public final class StickerPackCollectionInfo: ItemCollectionInfo, Equatable { encoder.encodeInt32(self.flags.rawValue, forKey: "f") encoder.encodeInt32(self.count, forKey: "n") - #if DEBUG + #if DEBUG && false var builder = FlatBufferBuilder(initialSize: 1024) let offset = self.encodeToFlatBuffers(builder: &builder) builder.finish(offset: offset) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift index 375710f705..af19a2fdf2 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift @@ -347,7 +347,7 @@ public final class TelegramChannel: Peer, Equatable { self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid") self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars") - #if DEBUG + #if DEBUG && false var builder = FlatBufferBuilder(initialSize: 1024) let offset = self.encodeToFlatBuffers(builder: &builder) builder.finish(offset: offset) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramGroup.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramGroup.swift index 975cab50bc..aacc14a215 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramGroup.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramGroup.swift @@ -207,7 +207,7 @@ public final class TelegramGroup: Peer, Equatable { self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0) self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0)) - #if DEBUG + #if DEBUG && false var builder = FlatBufferBuilder(initialSize: 1024) let offset = self.encodeToFlatBuffers(builder: &builder) builder.finish(offset: offset) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift index 2f396b8031..981c09d4c6 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift @@ -698,8 +698,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable { } else if let lhsWrappedData = lhs._wrappedData, let rhsWrappedData = rhs._wrappedData { return lhsWrappedData == rhsWrappedData } else { - assertionFailure() - return false + return lhs._parse() == rhs._parse() } } } @@ -903,13 +902,6 @@ public final class TelegramMediaFile: Media, Equatable, Codable { 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 { self.fileId = MediaId(namespace: flatBuffersObject.fileId.namespace, id: flatBuffersObject.fileId.id) self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0 ) } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift index 71ade1cead..78df24b4f2 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift @@ -21,10 +21,21 @@ private let cloudSoundMapping: [Int32: Int64] = [ 108: 5078299559046677216, 109: 5078299559046677217, 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 { case modern diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift index dcc7911f07..fb5cd2970d 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift @@ -331,7 +331,7 @@ public final class TelegramUser: Peer, Equatable { self.subscriberCount = decoder.decodeOptionalInt32ForKey("ssc") self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid") - #if DEBUG + #if DEBUG && false var builder = FlatBufferBuilder(initialSize: 1024) let offset = self.encodeToFlatBuffers(builder: &builder) builder.finish(offset: offset) diff --git a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift index 71c8071ddf..cb3b5a8c40 100644 --- a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift @@ -642,3 +642,22 @@ public func _internal_parseMediaAttachment(data: Data) -> Media? { 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 + } +} diff --git a/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift b/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift index 697670cb05..bcc088c7a9 100644 --- a/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift @@ -14,7 +14,18 @@ private let modernSoundsNamePaths: [KeyPath] = [ \.NotificationsSound_Keys, \.NotificationsSound_Popcorn, \.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] = [ diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift index 7665ed8d47..44698bdff0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift @@ -1116,7 +1116,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { var centerAnimation: TelegramMediaFile? - centerAnimation = messageEffect.staticIcon + centerAnimation = messageEffect.staticIcon?._parse() node.update( context: arguments.context, diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift index 5946804836..4b569bba1e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift @@ -2286,7 +2286,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr if automaticDownload != .none, let file = media as? TelegramMediaFile, NativeVideoContent.isHLSVideo(file: file) { 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 + 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 in guard let fileAndRange else { return .complete() diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageItemView/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Components/Chat/ChatMessageItemView/Sources/ChatMessageItemView.swift index 0a346026bc..8634e2b9d2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageItemView/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageItemView/Sources/ChatMessageItemView.swift @@ -938,13 +938,13 @@ open class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol { } self.playedEffectAnimation = true - if let effectAnimation = effect.effectAnimation { + if let effectAnimation = effect.effectAnimation?._parse() { self.playEffectAnimation(resource: effectAnimation.resource) if self.fetchEffectDisposable == nil { self.fetchEffectDisposable = freeMediaFileResourceInteractiveFetched(account: item.context.account, userLocation: .other, fileReference: .standalone(media: effectAnimation), resource: effectAnimation.resource).startStrict() } } else { - let effectSticker = effect.effectSticker + let effectSticker = effect.effectSticker._parse() if let effectFile = effectSticker.videoThumbnails.first { self.playEffectAnimation(resource: effectFile.resource) if self.fetchEffectDisposable == nil { diff --git a/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift b/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift index be3736f8ce..d817a3b4b7 100644 --- a/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift +++ b/submodules/TelegramUI/Components/Chat/TopMessageReactions/Sources/TopMessageReactions.swift @@ -501,7 +501,7 @@ public func effectMessageReactions(context: AccountContext) -> Signal<[ReactionI } existingIds.insert(messageEffect.id) - let mainFile = TelegramMediaFile.Accessor(messageEffect.effectSticker) + let mainFile = messageEffect.effectSticker result.append(ReactionItem( reaction: ReactionItem.Reaction(rawValue: .custom(messageEffect.id)), diff --git a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift index b942c311a5..a8fe5fc285 100644 --- a/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift +++ b/submodules/TelegramUI/Components/EmojiTextAttachmentView/Sources/EmojiTextAttachmentView.swift @@ -82,18 +82,20 @@ public func generateTopicIcon(title: String, backgroundColors: [UIColor], stroke }) } -public enum AnimationCacheAnimationType { +public enum AnimationCacheAnimationType: Equatable { case still case lottie - case video + case video(isVP9: Bool) } public extension AnimationCacheAnimationType { init(file: TelegramMediaFile) { if file.isVideoSticker || file.isVideoEmoji { - self = .video + self = .video(isVP9: true) } else if file.isAnimatedSticker { self = .lottie + } else if file.isVideo { + self = .video(isVP9: false) } else { self = .still } @@ -122,8 +124,8 @@ public func animationCacheFetchFile(postbox: Postbox, userLocation: MediaResourc } switch type { - case .video: - cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor) + case let .video(isVP9): + 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: guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else { options.writer.finish() @@ -153,8 +155,8 @@ public func animationCacheLoadLocalFile(name: String, type: AnimationCacheAnimat } switch type { - case .video: - cacheVideoAnimation(path: result, width: Int(options.size.width), height: Int(options.size.height), writer: options.writer, firstFrameOnly: options.firstFrameOnly, customColor: customColor) + case let .video(isVP9): + 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: guard let data = try? Data(contentsOf: URL(fileURLWithPath: result)) else { options.writer.finish() diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiKeyboardItemLayer.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiKeyboardItemLayer.swift index db8ad96529..9e693c07c7 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiKeyboardItemLayer.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiKeyboardItemLayer.swift @@ -33,7 +33,7 @@ public final class EmojiKeyboardItemLayer: MultiAnimationRenderTarget { case locked case featured case text(String) - case customFile(TelegramMediaFile) + case customFile(TelegramMediaFile.Accessor) } public let item: EmojiPagerContentComponent.Item diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 6811ddf78d..d8cb082c80 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -43,10 +43,10 @@ public final class EntityKeyboardAnimationData: Equatable { case gift(String) } - public enum ItemType { + public enum ItemType: Equatable { case still case lottie - case video + case video(isVP9: Bool) var animationCacheAnimationType: AnimationCacheAnimationType { switch self { @@ -54,8 +54,8 @@ public final class EntityKeyboardAnimationData: Equatable { return .still case .lottie: return .lottie - case .video: - return .video + case let .video(isVP9): + 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) { let type: ItemType if file.isVideoSticker || file.isVideoEmoji { - type = .video + type = .video(isVP9: true) } else if file.isAnimatedSticker { type = .lottie + } else if file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -406,7 +408,7 @@ public final class EmojiPagerContentComponent: Component { case locked case premium case text(String) - case customFile(TelegramMediaFile) + case customFile(TelegramMediaFile.Accessor) } public enum TintMode: Equatable { diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift index e5631ac485..65d4422d7a 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift @@ -287,7 +287,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -1390,7 +1392,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -1477,7 +1481,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -1774,7 +1780,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -2011,7 +2019,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -2090,7 +2100,9 @@ public extension EmojiPagerContentComponent { if item.file.isAnimatedSticker { type = .lottie } else if item.file.isVideoEmoji || item.file.isVideoSticker { - type = .video + type = .video(isVP9: true) + } else if item.file.isVideo { + type = .video(isVP9: false) } else { type = .still } @@ -2234,7 +2246,7 @@ public extension EmojiPagerContentComponent { continue } - let itemFile: TelegramMediaFile = item.effectSticker + let itemFile = item.effectSticker var tintMode: Item.TintMode = .none 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( animationData: animationData, content: .animation(animationData), - itemFile: TelegramMediaFile.Accessor(itemFile), + itemFile: itemFile, subgroupId: nil, icon: icon, tintMode: tintMode diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/PremiumBadgeView.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/PremiumBadgeView.swift index d2d5c1f6c7..e3d20690f8 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/PremiumBadgeView.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/PremiumBadgeView.swift @@ -81,7 +81,7 @@ final class PremiumBadgeView: UIView { context: self.context, userLocation: .other, attemptSynchronousLoad: false, - file: customFile, + file: customFile._parse(), cache: self.context.animationCache, renderer: self.context.animationRenderer, unique: false, diff --git a/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift b/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift index 77a642802d..5eaa7014cb 100644 --- a/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift +++ b/submodules/TelegramUI/Components/VideoAnimationCache/Sources/VideoAnimationCache.swift @@ -18,9 +18,9 @@ private func roundUp(_ numToRound: Int, multiple: Int) -> Int { 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 = { - 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 } let frameDuration = 1.0 / Double(frameSource.frameRate) diff --git a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift index b54ea987e4..40722128c5 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputActionButtonsNode.swift @@ -102,7 +102,7 @@ private final class EffectBadgeView: UIView { } let effectIconContent: ChatSendMessageScreenEffectIcon.Content if let staticIcon = effect.staticIcon { - effectIconContent = .file(staticIcon) + effectIconContent = .file(staticIcon._parse()) } else { effectIconContent = .text(effect.emoticon) }