mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '809db5605297aaad60e93e0579fd0681b63abec0' into experimental-3
# Conflicts: # Telegram/Telegram-iOS/en.lproj/Localizable.strings
This commit is contained in:
commit
8edb5f967c
@ -7253,3 +7253,6 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Conversation.ReadAllReactions" = "Read All Reactions";
|
||||
"ChatList.UserReacted" = "Reacted %@ to your message";
|
||||
|
||||
"SharedMedia.CommonGroupCount_1" = "%@ group in common";
|
||||
"SharedMedia.CommonGroupCount_any" = "%@ groups in common";
|
||||
|
@ -679,7 +679,20 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
|
||||
Queue.mainQueue().after(1.0) {
|
||||
var firstItem: StickerPackItem?
|
||||
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
|
||||
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: firstStickerItem.mimeType, size: nil, attributes: [.FileName(fileName: ""), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
|
||||
var fileAttributes: [TelegramMediaFileAttribute] = []
|
||||
if firstStickerItem.mimeType == "video/webm" {
|
||||
fileAttributes.append(.FileName(fileName: "sticker.webm"))
|
||||
fileAttributes.append(.Animated)
|
||||
fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil))
|
||||
} else if firstStickerItem.mimeType == "application/x-tgsticker" {
|
||||
fileAttributes.append(.FileName(fileName: "sticker.tgs"))
|
||||
fileAttributes.append(.Animated)
|
||||
fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil))
|
||||
} else {
|
||||
fileAttributes.append(.FileName(fileName: "sticker.webp"))
|
||||
}
|
||||
fileAttributes.append(.ImageSize(size: firstStickerItem.dimensions))
|
||||
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: firstStickerItem.mimeType, size: nil, attributes: fileAttributes), indexKeys: [])
|
||||
}
|
||||
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
|
||||
if case .info = action {
|
||||
|
@ -25,6 +25,7 @@ swift_library(
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/LocationResources:LocationResources",
|
||||
"//submodules/UndoUI:UndoUI",
|
||||
"//submodules/Translate:Translate",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -16,6 +16,7 @@ import OpenInExternalAppUI
|
||||
import LocationUI
|
||||
import UndoUI
|
||||
import ContextUI
|
||||
import Translate
|
||||
|
||||
final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private weak var controller: InstantPageController?
|
||||
@ -1020,23 +1021,46 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
coveringRect = coveringRect.union(rects[i])
|
||||
}
|
||||
|
||||
let controller = ContextMenuController(actions: [ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.strings.Conversation_ContextMenuCopy), action: {
|
||||
let context = self.context
|
||||
let strings = self.strings
|
||||
let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
let translationSettings: TranslationSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
|
||||
translationSettings = current
|
||||
} else {
|
||||
translationSettings = TranslationSettings.defaultSettings
|
||||
}
|
||||
|
||||
var actions: [ContextMenuAction] = [ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuCopy, accessibilityLabel: strings.Conversation_ContextMenuCopy), action: {
|
||||
UIPasteboard.general.string = text
|
||||
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
}), ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuShare, accessibilityLabel: strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let strongSelf = self, let webPage = strongSelf.webPage, case let .Loaded(content) = webPage.content {
|
||||
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
|
||||
}
|
||||
})])
|
||||
})]
|
||||
|
||||
|
||||
if canTranslateText(context: context, text: text, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) {
|
||||
actions.append(ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuTranslate, accessibilityLabel: strings.Conversation_ContextMenuTranslate), action: {
|
||||
translateText(context: context, text: text)
|
||||
}))
|
||||
}
|
||||
|
||||
let controller = ContextMenuController(actions: actions)
|
||||
controller.dismissed = { [weak self] in
|
||||
self?.updateTextSelectionRects([], text: nil)
|
||||
}
|
||||
self.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||
self?.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
return (strongSelf.scrollNode, coveringRect.insetBy(dx: -3.0, dy: -3.0), strongSelf, strongSelf.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
textSelectionNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18)
|
||||
} else if let textSelectionNode = self.textSelectionNode {
|
||||
self.textSelectionNode = nil
|
||||
|
@ -22,6 +22,7 @@ swift_library(
|
||||
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/ShimmerEffect:ShimmerEffect",
|
||||
"//submodules/SoftwareVideo:SoftwareVideo",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -12,6 +12,7 @@ import StickerResources
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import SoftwareVideo
|
||||
|
||||
public struct ItemListStickerPackItemEditing: Equatable {
|
||||
public var editable: Bool
|
||||
@ -121,7 +122,7 @@ public final class ItemListStickerPackItem: ListViewItem, ItemListItem {
|
||||
|
||||
public enum StickerPackThumbnailItem: Equatable {
|
||||
case still(TelegramMediaImageRepresentation)
|
||||
case animated(MediaResource, PixelDimensions)
|
||||
case animated(MediaResource, PixelDimensions, Bool)
|
||||
|
||||
public static func ==(lhs: StickerPackThumbnailItem, rhs: StickerPackThumbnailItem) -> Bool {
|
||||
switch lhs {
|
||||
@ -131,8 +132,8 @@ public enum StickerPackThumbnailItem: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .animated(lhsResource, lhsDimensions):
|
||||
if case let .animated(rhsResource, rhsDimensions) = rhs, lhsResource.isEqual(to: rhsResource), lhsDimensions == rhsDimensions {
|
||||
case let .animated(lhsResource, lhsDimensions, lhsIsVideo):
|
||||
if case let .animated(rhsResource, rhsDimensions, rhsIsVideo) = rhs, lhsResource.isEqual(to: rhsResource), lhsDimensions == rhsDimensions, lhsIsVideo == rhsIsVideo {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -158,6 +159,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
fileprivate let imageNode: TransformImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let unreadNode: ASImageNode
|
||||
private let titleNode: TextNode
|
||||
@ -194,7 +196,9 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
let isVisible = self.visibility != .none
|
||||
|
||||
if wasVisible != isVisible {
|
||||
self.animationNode?.visibility = isVisible && (self.layoutParams?.0.playAnimatedStickers ?? true)
|
||||
let visibility = isVisible && (self.layoutParams?.0.playAnimatedStickers ?? true)
|
||||
self.videoNode?.update(isPlaying: visibility)
|
||||
self.animationNode?.visibility = visibility
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -471,16 +475,15 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = item.packInfo.thumbnail {
|
||||
if item.packInfo.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
if item.packInfo.flags.contains(.isAnimated) || item.packInfo.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, item.packInfo.flags.contains(.isVideo))
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: item.packInfo.id.id, accessHash: item.packInfo.accessHash), resource: thumbnail.resource)
|
||||
} else if let item = item.topItem {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -507,7 +510,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
imageApply = makeImageLayout(TransformImageArguments(corners: ImageCorners(), imageSize: stillImageSize, boundingSize: stillImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: item.account.postbox, resource: representation.resource, nilIfEmpty: true)
|
||||
}
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, _):
|
||||
imageSize = imageBoundingSize
|
||||
|
||||
if fileUpdated {
|
||||
@ -745,14 +748,35 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
let boundingSize = CGSize(width: 34.0, height: 34.0)
|
||||
if let thumbnailItem = thumbnailItem, let imageSize = imageSize {
|
||||
let imageFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset + editingOffset + 15.0 + floor((boundingSize.width - imageSize.width) / 2.0), y: floor((layout.contentSize.height - imageSize.height) / 2.0)), size: imageSize)
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
|
||||
var thumbnailDimensions = PixelDimensions(width: 512, height: 512)
|
||||
switch thumbnailItem {
|
||||
case let .still(representation):
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
thumbnailDimensions = representation.dimensions
|
||||
case let .animated(resource, _):
|
||||
transition.updateFrame(node: strongSelf.imageNode, frame: imageFrame)
|
||||
case let .animated(resource, _, isVideo):
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = strongSelf.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
videoNode = VideoStickerNode()
|
||||
strongSelf.videoNode = videoNode
|
||||
strongSelf.addSubnode(videoNode)
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: item.account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
videoNode.updateLayout(size: imageFrame.size)
|
||||
videoNode.update(isPlaying: strongSelf.visibility != .none && item.playAnimatedStickers)
|
||||
videoNode.isHidden = !item.playAnimatedStickers
|
||||
strongSelf.imageNode.isHidden = item.playAnimatedStickers
|
||||
if let videoNode = strongSelf.videoNode {
|
||||
transition.updateFrame(node: videoNode, frame: imageFrame)
|
||||
}
|
||||
} else {
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let current = strongSelf.animationNode {
|
||||
animationNode = current
|
||||
@ -770,6 +794,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
transition.updateFrame(node: animationNode, frame: imageFrame)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let placeholderNode = strongSelf.placeholderNode {
|
||||
placeholderNode.frame = imageFrame
|
||||
|
@ -307,47 +307,58 @@ public final class FFMpegMediaVideoFrameDecoder: MediaTrackFrameDecoder {
|
||||
let bytesPerRowUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
|
||||
let bytesPerRowA = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 2)
|
||||
|
||||
var base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
||||
var requiresAlphaMultiplication = false
|
||||
|
||||
var base: UnsafeMutableRawPointer
|
||||
if case .YUVA = frame.pixelFormat {
|
||||
requiresAlphaMultiplication = true
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!
|
||||
if bytesPerRowA == frame.lineSize[3] {
|
||||
memcpy(base, frame.data[3]!, bytesPerRowA * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[3]!
|
||||
let lineSize = Int(frame.lineSize[3])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowA)
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!
|
||||
if bytesPerRowY == frame.lineSize[0] {
|
||||
memcpy(base, frame.data[0]!, bytesPerRowY * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[0]!
|
||||
let linesize = Int(frame.lineSize[0])
|
||||
let lineSize = Int(frame.lineSize[0])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, linesize)
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowY)
|
||||
src = src.advanced(by: linesize)
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
|
||||
if requiresAlphaMultiplication {
|
||||
var y = vImage_Buffer(data: CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0)!, height: vImagePixelCount(frame.height), width: vImagePixelCount(bytesPerRowY), rowBytes: bytesPerRowY)
|
||||
var a = vImage_Buffer(data: CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!, height: vImagePixelCount(frame.height), width: vImagePixelCount(bytesPerRowY), rowBytes: bytesPerRowA)
|
||||
let _ = vImagePremultiplyData_Planar8(&y, &a, &y, vImage_Flags(kvImageDoNotTile))
|
||||
}
|
||||
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1)!
|
||||
if bytesPerRowUV == frame.lineSize[1] * 2 {
|
||||
memcpy(base, dstPlane, Int(frame.height / 2) * bytesPerRowUV)
|
||||
} else {
|
||||
var dest = base
|
||||
var src = dstPlane
|
||||
let linesize = Int(frame.lineSize[1]) * 2
|
||||
let lineSize = Int(frame.lineSize[1]) * 2
|
||||
for _ in 0 ..< Int(frame.height / 2) {
|
||||
memcpy(dest, src, linesize)
|
||||
memcpy(dest, src, lineSize)
|
||||
dest = dest.advanced(by: bytesPerRowUV)
|
||||
src = src.advanced(by: linesize)
|
||||
}
|
||||
}
|
||||
|
||||
if case .YUVA = frame.pixelFormat {
|
||||
base = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 2)!
|
||||
if bytesPerRowA == frame.lineSize[3] {
|
||||
memcpy(base, frame.data[3]!, bytesPerRowA * Int(frame.height))
|
||||
} else {
|
||||
var dest = base
|
||||
var src = frame.data[3]!
|
||||
let linesize = Int(frame.lineSize[3])
|
||||
for _ in 0 ..< Int(frame.height) {
|
||||
memcpy(dest, src, linesize)
|
||||
dest = dest.advanced(by: bytesPerRowA)
|
||||
src = src.advanced(by: linesize)
|
||||
}
|
||||
src = src.advanced(by: lineSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
self.isReady.set(videoNode.ready |> map { return true })
|
||||
}
|
||||
|
||||
func setup(item: PeerInfoAvatarListItem, progress: Signal<Float?, NoError>? = nil, synchronous: Bool, fullSizeOnly: Bool = false) {
|
||||
func setup(item: PeerInfoAvatarListItem, isMain: Bool, progress: Signal<Float?, NoError>? = nil, synchronous: Bool, fullSizeOnly: Bool = false) {
|
||||
self.item = item
|
||||
self.progress = progress
|
||||
|
||||
@ -385,7 +385,7 @@ public final class PeerInfoAvatarListItemNode: ASDisplayNode {
|
||||
id = self.peer.id.id._internalGetInt64Value()
|
||||
}
|
||||
}
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: true, attemptSynchronously: synchronous, skipThumbnail: fullSizeOnly), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: self.context.account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: true, attemptSynchronously: synchronous, skipThumbnail: fullSizeOnly, skipBlurIfLarge: isMain), attemptSynchronously: synchronous, dispatchOnDisplayLink: false)
|
||||
|
||||
if let video = videoRepresentations.last, let peerReference = PeerReference(self.peer) {
|
||||
let videoFileReference = FileMediaReference.avatarList(peer: peerReference, media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: video.representation.resource, previewRepresentations: representations.map { $0.representation }, videoThumbnails: [], immediateThumbnailData: immediateThumbnailData, mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: video.representation.dimensions, flags: [])]))
|
||||
@ -1157,13 +1157,13 @@ public final class PeerInfoAvatarListContainerNode: ASDisplayNode {
|
||||
if case .custom = self.items[i], self.updateCustomItemsOnlySynchronously {
|
||||
synchronous = true
|
||||
}
|
||||
current.setup(item: self.items[i], synchronous: synchronous && i == self.currentIndex, fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
current.setup(item: self.items[i], isMain: i == 0, synchronous: synchronous && i == self.currentIndex, fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
}
|
||||
} else if let peer = self.peer {
|
||||
wasAdded = true
|
||||
let addedItemNode = PeerInfoAvatarListItemNode(context: self.context, peer: peer)
|
||||
itemNode = addedItemNode
|
||||
addedItemNode.setup(item: self.items[i], progress: i == 0 ? self.additionalEntryProgress : nil, synchronous: (i == 0 && i == self.currentIndex) || (synchronous && i == self.currentIndex), fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
addedItemNode.setup(item: self.items[i], isMain: i == 0, progress: i == 0 ? self.additionalEntryProgress : nil, synchronous: (i == 0 && i == self.currentIndex) || (synchronous && i == self.currentIndex), fullSizeOnly: self.firstFullSizeOnly && i == 0)
|
||||
self.itemNodes[self.items[i].id] = addedItemNode
|
||||
self.contentNode.addSubnode(addedItemNode)
|
||||
}
|
||||
|
@ -2335,7 +2335,7 @@ private func avatarGalleryPhotoDatas(account: Account, fileReference: FileMediaR
|
||||
}
|
||||
}
|
||||
|
||||
public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false, skipThumbnail: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepresentationWithReference], immediateThumbnailData: Data?, autoFetchFullSize: Bool = false, attemptSynchronously: Bool = false, skipThumbnail: Bool = false, skipBlurIfLarge: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let signal = avatarGalleryPhotoDatas(account: account, representations: representations, immediateThumbnailData: immediateThumbnailData, autoFetchFullSize: autoFetchFullSize, attemptSynchronously: attemptSynchronously)
|
||||
|
||||
return signal
|
||||
@ -2385,7 +2385,8 @@ public func chatAvatarGalleryPhoto(account: Account, representations: [ImageRepr
|
||||
|
||||
var blurredThumbnailImage: UIImage?
|
||||
if let thumbnailImage = thumbnailImage, !skipThumbnail {
|
||||
if max(thumbnailImage.width, thumbnailImage.height) > 200 {
|
||||
let maxThumbnailSide = max(thumbnailImage.width, thumbnailImage.height)
|
||||
if maxThumbnailSide > 200 || (maxThumbnailSide > 120 && maxThumbnailSide < 200 && skipBlurIfLarge) {
|
||||
blurredThumbnailImage = UIImage(cgImage: thumbnailImage)
|
||||
} else {
|
||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||
|
@ -354,7 +354,8 @@ public final class SparseDiscreteScrollingArea: ASDisplayNode {
|
||||
backgroundColor: theme.list.itemBlocksBackgroundColor,
|
||||
shadowColor: .black,
|
||||
foregroundColor: theme.list.itemPrimaryTextColor,
|
||||
dateString: "Date"
|
||||
dateString: "Date",
|
||||
previousDateString: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: containerSize
|
||||
|
@ -555,22 +555,170 @@ private final class ShadowRoundedRectangle: Component {
|
||||
}
|
||||
}
|
||||
|
||||
public final class RollingText: Component {
|
||||
private final class MeasureState: Equatable {
|
||||
let attributedText: NSAttributedString
|
||||
let availableSize: CGSize
|
||||
let size: CGSize
|
||||
|
||||
init(attributedText: NSAttributedString, availableSize: CGSize, size: CGSize) {
|
||||
self.attributedText = attributedText
|
||||
self.availableSize = availableSize
|
||||
self.size = size
|
||||
}
|
||||
|
||||
static func ==(lhs: MeasureState, rhs: MeasureState) -> Bool {
|
||||
if !lhs.attributedText.isEqual(rhs.attributedText) {
|
||||
return false
|
||||
}
|
||||
if lhs.availableSize != rhs.availableSize {
|
||||
return false
|
||||
}
|
||||
if lhs.size != rhs.size {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public final class View: UIView {
|
||||
private var measureState: MeasureState?
|
||||
private var containerView: UIImageView
|
||||
|
||||
private var snapshotView: UIView?
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
self.containerView = UIImageView()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.containerView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func update(component: RollingText, availableSize: CGSize) -> CGSize {
|
||||
let attributedText = NSAttributedString(string: component.text, attributes: [
|
||||
NSAttributedString.Key.font: component.font,
|
||||
NSAttributedString.Key.foregroundColor: component.color
|
||||
])
|
||||
|
||||
if let measureState = self.measureState {
|
||||
if measureState.attributedText.isEqual(to: attributedText) && measureState.availableSize == availableSize {
|
||||
return measureState.size
|
||||
}
|
||||
}
|
||||
|
||||
var boundingRect = attributedText.boundingRect(with: availableSize, options: .usesLineFragmentOrigin, context: nil)
|
||||
boundingRect.size.width = ceil(boundingRect.size.width)
|
||||
boundingRect.size.height = ceil(boundingRect.size.height)
|
||||
|
||||
if let animation = component.animation {
|
||||
if let snapshotView = self.snapshotView {
|
||||
self.snapshotView = nil
|
||||
snapshotView.removeFromSuperview()
|
||||
|
||||
self.containerView.layer.removeAnimation(forKey: "opacity")
|
||||
}
|
||||
if let snapshotView = self.containerView.snapshotView(afterScreenUpdates: true) {
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animation ? 12.0 : -12.0), duration: 0.2, removeOnCompletion: false, additive: true, completion: { [weak self, weak snapshotView] _ in
|
||||
self?.snapshotView = nil
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
snapshotView.frame = CGRect(origin: CGPoint(x: boundingRect.width - snapshotView.frame.width, y: 0.0), size: snapshotView.frame.size)
|
||||
|
||||
self.addSubview(snapshotView)
|
||||
self.snapshotView = snapshotView
|
||||
|
||||
self.containerView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.containerView.layer.animatePosition(from: animation ? CGPoint(x: 0.0, y: -12.0) : CGPoint(x: 0.0, y: 12.0), to: CGPoint(), duration: 0.2, additive: true)
|
||||
}
|
||||
}
|
||||
|
||||
self.containerView.frame = CGRect(origin: CGPoint(), size: boundingRect.size)
|
||||
|
||||
let measureState = MeasureState(attributedText: attributedText, availableSize: availableSize, size: boundingRect.size)
|
||||
if #available(iOS 10.0, *) {
|
||||
let renderer = UIGraphicsImageRenderer(bounds: CGRect(origin: CGPoint(), size: measureState.size))
|
||||
let image = renderer.image { context in
|
||||
UIGraphicsPushContext(context.cgContext)
|
||||
measureState.attributedText.draw(at: CGPoint())
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
self.containerView.image = image
|
||||
} else {
|
||||
UIGraphicsBeginImageContextWithOptions(measureState.size, false, 0.0)
|
||||
measureState.attributedText.draw(at: CGPoint())
|
||||
self.containerView.image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
|
||||
self.measureState = measureState
|
||||
|
||||
return boundingRect.size
|
||||
}
|
||||
}
|
||||
|
||||
public let text: String
|
||||
public let font: UIFont
|
||||
public let color: UIColor
|
||||
public let animation: Bool?
|
||||
|
||||
public init(text: String, font: UIFont, color: UIColor, animation: Bool?) {
|
||||
self.text = text
|
||||
self.font = font
|
||||
self.color = color
|
||||
self.animation = animation
|
||||
}
|
||||
|
||||
public static func ==(lhs: RollingText, rhs: RollingText) -> Bool {
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
if !lhs.font.isEqual(rhs.font) {
|
||||
return false
|
||||
}
|
||||
if !lhs.color.isEqual(rhs.color) {
|
||||
return false
|
||||
}
|
||||
if lhs.animation != rhs.animation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
public func update(view: View, availableSize: CGSize, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
|
||||
let backgroundColor: UIColor
|
||||
let shadowColor: UIColor
|
||||
let foregroundColor: UIColor
|
||||
let dateString: String
|
||||
let previousDateString: String?
|
||||
|
||||
init(
|
||||
backgroundColor: UIColor,
|
||||
shadowColor: UIColor,
|
||||
foregroundColor: UIColor,
|
||||
dateString: String
|
||||
dateString: String,
|
||||
previousDateString: String?
|
||||
) {
|
||||
self.backgroundColor = backgroundColor
|
||||
self.shadowColor = shadowColor
|
||||
self.foregroundColor = foregroundColor
|
||||
self.dateString = dateString
|
||||
self.previousDateString = previousDateString
|
||||
}
|
||||
|
||||
static func ==(lhs: SparseItemGridScrollingIndicatorComponent, rhs: SparseItemGridScrollingIndicatorComponent) -> Bool {
|
||||
@ -586,19 +734,90 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
|
||||
if lhs.dateString != rhs.dateString {
|
||||
return false
|
||||
}
|
||||
if lhs.previousDateString != rhs.previousDateString {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let rect = Child(ShadowRoundedRectangle.self)
|
||||
let text = Child(Text.self)
|
||||
let textMonth = Child(RollingText.self)
|
||||
let textYear = Child(RollingText.self)
|
||||
|
||||
return { context in
|
||||
let text = text.update(
|
||||
component: Text(
|
||||
text: context.component.dateString,
|
||||
font: Font.medium(13.0),
|
||||
color: context.component.foregroundColor
|
||||
let components = context.component.dateString.components(separatedBy: " ")
|
||||
let month = components.first ?? ""
|
||||
let year = components.last ?? ""
|
||||
|
||||
var monthAnimation: Bool?
|
||||
var yearAnimation: Bool?
|
||||
if let previousDateString = context.component.previousDateString {
|
||||
func monthValue(_ string: String) -> Int {
|
||||
switch string {
|
||||
case "January":
|
||||
return 1
|
||||
case "February":
|
||||
return 2
|
||||
case "March":
|
||||
return 3
|
||||
case "April":
|
||||
return 4
|
||||
case "May":
|
||||
return 5
|
||||
case "June":
|
||||
return 6
|
||||
case "July":
|
||||
return 7
|
||||
case "August":
|
||||
return 8
|
||||
case "September":
|
||||
return 9
|
||||
case "October":
|
||||
return 10
|
||||
case "November":
|
||||
return 11
|
||||
case "December":
|
||||
return 12
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
let monValue = monthValue(month)
|
||||
let yearValue = Int(year) ?? 0
|
||||
|
||||
let previousComponents = previousDateString.components(separatedBy: " ")
|
||||
let previousMonth = previousComponents.first ?? ""
|
||||
let previousYear = previousComponents.last ?? ""
|
||||
|
||||
let previousMonValue = monthValue(previousMonth)
|
||||
let previousYearValue = Int(previousYear) ?? 0
|
||||
|
||||
if yearValue != previousYearValue {
|
||||
yearAnimation = yearValue > previousYearValue
|
||||
monthAnimation = yearAnimation
|
||||
} else if monValue != previousMonValue {
|
||||
monthAnimation = monValue > previousMonValue
|
||||
}
|
||||
}
|
||||
|
||||
let textMonth = textMonth.update(
|
||||
component: RollingText(
|
||||
text: month,
|
||||
font: Font.with(size: 13.0, design: .regular, weight: .medium, traits: .monospacedNumbers),
|
||||
color: context.component.foregroundColor,
|
||||
animation: monthAnimation
|
||||
),
|
||||
availableSize: CGSize(width: 200.0, height: 100.0),
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
let textYear = textYear.update(
|
||||
component: RollingText(
|
||||
text: year,
|
||||
font: Font.with(size: 13.0, design: .regular, weight: .medium, traits: .monospacedNumbers),
|
||||
color: context.component.foregroundColor,
|
||||
animation: yearAnimation
|
||||
),
|
||||
availableSize: CGSize(width: 200.0, height: 100.0),
|
||||
transition: .immediate
|
||||
@ -608,7 +827,7 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
|
||||
component: ShadowRoundedRectangle(
|
||||
color: context.component.backgroundColor
|
||||
),
|
||||
availableSize: CGSize(width: text.size.width + 26.0, height: 32.0),
|
||||
availableSize: CGSize(width: textMonth.size.width + 3.0 + textYear.size.width + 26.0, height: 32.0),
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
@ -621,9 +840,15 @@ final class SparseItemGridScrollingIndicatorComponent: CombinedComponent {
|
||||
.position(CGPoint(x: rectFrame.midX, y: rectFrame.midY))
|
||||
)
|
||||
|
||||
let textFrame = text.size.centered(in: rectFrame)
|
||||
context.add(text
|
||||
.position(CGPoint(x: textFrame.midX, y: textFrame.midY))
|
||||
let offset = CGSize(width: textMonth.size.width + 3.0 + textYear.size.width, height: textMonth.size.height).centered(in: rectFrame)
|
||||
|
||||
let monthTextFrame = textMonth.size.leftCentered(in: rectFrame).offsetBy(dx: offset.minX, dy: 0.0)
|
||||
let yearTextFrame = textYear.size.leftCentered(in: rectFrame).offsetBy(dx: offset.minX + monthTextFrame.width + 3.0, dy: 0.0)
|
||||
context.add(textMonth
|
||||
.position(CGPoint(x: monthTextFrame.midX, y: monthTextFrame.midY))
|
||||
)
|
||||
context.add(textYear
|
||||
.position(CGPoint(x: yearTextFrame.midX, y: yearTextFrame.midY))
|
||||
)
|
||||
|
||||
return rect.size
|
||||
@ -900,6 +1125,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
||||
self.hapticFeedback.tap()
|
||||
}
|
||||
|
||||
private var dateString: String?
|
||||
|
||||
public func update(
|
||||
containerSize: CGSize,
|
||||
containerInsets: UIEdgeInsets,
|
||||
@ -912,6 +1139,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
||||
) {
|
||||
self.containerSize = containerSize
|
||||
self.theme = theme
|
||||
let previousDateString = self.dateString
|
||||
self.dateString = dateString
|
||||
|
||||
if self.dateIndicator.alpha.isZero {
|
||||
let transition: ContainedViewLayoutTransition = .immediate
|
||||
@ -928,7 +1157,8 @@ public final class SparseItemGridScrollingArea: ASDisplayNode {
|
||||
backgroundColor: theme.list.itemBlocksBackgroundColor,
|
||||
shadowColor: .black,
|
||||
foregroundColor: theme.list.itemPrimaryTextColor,
|
||||
dateString: dateString
|
||||
dateString: dateString,
|
||||
previousDateString: previousDateString
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: containerSize
|
||||
|
@ -24,6 +24,9 @@ public struct StickerPackCollectionInfoFlags: OptionSet {
|
||||
if flags.contains(StickerPackCollectionInfoFlags.isAnimated) {
|
||||
rawValue |= StickerPackCollectionInfoFlags.isAnimated.rawValue
|
||||
}
|
||||
if flags.contains(StickerPackCollectionInfoFlags.isVideo) {
|
||||
rawValue |= StickerPackCollectionInfoFlags.isVideo.rawValue
|
||||
}
|
||||
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
@ -31,6 +34,7 @@ public struct StickerPackCollectionInfoFlags: OptionSet {
|
||||
public static let isMasks = StickerPackCollectionInfoFlags(rawValue: 1 << 0)
|
||||
public static let isOfficial = StickerPackCollectionInfoFlags(rawValue: 1 << 1)
|
||||
public static let isAnimated = StickerPackCollectionInfoFlags(rawValue: 1 << 2)
|
||||
public static let isVideo = StickerPackCollectionInfoFlags(rawValue: 1 << 3)
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,6 +26,11 @@ public struct TelegramChatAdminRightsFlags: OptionSet, Hashable {
|
||||
return [.canChangeInfo, .canPostMessages, .canEditMessages, .canDeleteMessages, .canBanUsers, .canInviteUsers, .canPinMessages, .canAddAdmins, .canBeAnonymous, .canManageCalls]
|
||||
}
|
||||
|
||||
public static var allChannel: TelegramChatAdminRightsFlags {
|
||||
return [.canChangeInfo, .canPostMessages, .canEditMessages, .canDeleteMessages, .canBanUsers, .canInviteUsers, .canPinMessages, .canAddAdmins, .canManageCalls]
|
||||
}
|
||||
|
||||
|
||||
public static var groupSpecific: TelegramChatAdminRightsFlags = [
|
||||
.canChangeInfo,
|
||||
.canDeleteMessages,
|
||||
|
@ -482,18 +482,15 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
|
||||
if self.mimeType == "video/webm" {
|
||||
return true
|
||||
}
|
||||
if let _ = self.fileName, self.mimeType == "video/webm" {
|
||||
if self.mimeType == "video/webm" {
|
||||
var hasSticker = false
|
||||
var hasAnimated = false
|
||||
for attribute in self.attributes {
|
||||
if case .Sticker = attribute {
|
||||
hasSticker = true
|
||||
}
|
||||
if case .Animated = attribute {
|
||||
hasAnimated = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return hasSticker && hasAnimated
|
||||
return hasSticker
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ private final class GroupsInCommonContextImpl {
|
||||
private let queue: Queue
|
||||
private let account: Account
|
||||
private let peerId: PeerId
|
||||
private let hintGroupInCommon: PeerId?
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
@ -30,10 +31,21 @@ private final class GroupsInCommonContextImpl {
|
||||
return self.stateValue.get()
|
||||
}
|
||||
|
||||
init(queue: Queue, account: Account, peerId: PeerId) {
|
||||
init(queue: Queue, account: Account, peerId: PeerId, hintGroupInCommon: PeerId?) {
|
||||
self.queue = queue
|
||||
self.account = account
|
||||
self.peerId = peerId
|
||||
self.hintGroupInCommon = hintGroupInCommon
|
||||
|
||||
if let hintGroupInCommon = hintGroupInCommon {
|
||||
let _ = (self.account.postbox.loadedPeerWithId(hintGroupInCommon)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] peer in
|
||||
if let strongSelf = self {
|
||||
strongSelf.peers.append(RenderedPeer(peer: peer))
|
||||
strongSelf.pushState()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self.loadMore(limit: 32)
|
||||
}
|
||||
@ -141,10 +153,10 @@ public final class GroupsInCommonContext {
|
||||
}
|
||||
}
|
||||
|
||||
public init(account: Account, peerId: PeerId) {
|
||||
public init(account: Account, peerId: PeerId, hintGroupInCommon: PeerId? = nil) {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return GroupsInCommonContextImpl(queue: queue, account: account, peerId: peerId)
|
||||
return GroupsInCommonContextImpl(queue: queue, account: account, peerId: peerId, hintGroupInCommon: hintGroupInCommon)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,7 @@ func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResour
|
||||
case let .progress(progress):
|
||||
return .single(.progress(progress))
|
||||
case let .inputFile(file):
|
||||
var flags: Int32 = 0
|
||||
flags |= (1 << 4)
|
||||
let flags: Int32 = 0
|
||||
var attributes: [Api.DocumentAttribute] = []
|
||||
attributes.append(.documentAttributeSticker(flags: 0, alt: alt, stickerset: .inputStickerSetEmpty, maskCoords: nil))
|
||||
attributes.append(.documentAttributeImageSize(w: dimensions.width, h: dimensions.height))
|
||||
@ -134,8 +133,13 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
|
||||
}
|
||||
if resources.count == stickers.count {
|
||||
var flags: Int32 = 0
|
||||
if case .animation = type {
|
||||
switch type {
|
||||
case .animation:
|
||||
flags |= (1 << 1)
|
||||
case .video:
|
||||
flags |= (1 << 4)
|
||||
default:
|
||||
break
|
||||
}
|
||||
var inputStickers: [Api.InputStickerSetItem] = []
|
||||
let stickerDocuments = thumbnail != nil ? resources.dropLast() : resources
|
||||
|
@ -43,6 +43,9 @@ extension StickerPackCollectionInfo {
|
||||
if (flags & (1 << 5)) != 0 {
|
||||
setFlags.insert(.isAnimated)
|
||||
}
|
||||
if (flags & (1 << 6)) != 0 {
|
||||
setFlags.insert(.isVideo)
|
||||
}
|
||||
|
||||
var thumbnailRepresentation: TelegramMediaImageRepresentation?
|
||||
var immediateThumbnailData: Data?
|
||||
|
@ -303,7 +303,7 @@ final class ChatBotInfoItemNode: ListViewItemNode {
|
||||
case let .url(url, concealed):
|
||||
self.item?.controllerInteraction.openUrl(url, concealed, nil, nil)
|
||||
case let .peerMention(peerId, _):
|
||||
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil)
|
||||
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil, nil)
|
||||
case let .textMention(name):
|
||||
self.item?.controllerInteraction.openPeerMention(name)
|
||||
case let .botCommand(command):
|
||||
|
@ -201,7 +201,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
||||
peerId = message.id.peerId
|
||||
}
|
||||
if let botPeer = botPeer, let addressName = botPeer.addressName {
|
||||
self.controllerInteraction.openPeer(peerId, .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: "@\(addressName) \(query)")), subject: nil, peekData: nil), nil)
|
||||
self.controllerInteraction.openPeer(peerId, .chat(textInputState: ChatTextInputState(inputText: NSAttributedString(string: "@\(addressName) \(query)")), subject: nil, peekData: nil), nil, nil)
|
||||
}
|
||||
}
|
||||
case .payment:
|
||||
@ -213,7 +213,7 @@ final class ChatButtonKeyboardInputNode: ChatInputNode {
|
||||
case let .setupPoll(isQuiz):
|
||||
self.controllerInteraction.openPollCreation(isQuiz)
|
||||
case let .openUserProfile(peerId):
|
||||
self.controllerInteraction.openPeer(peerId, .info, nil)
|
||||
self.controllerInteraction.openPeer(peerId, .info, nil, nil)
|
||||
}
|
||||
if dismissIfOnce {
|
||||
if let message = self.message {
|
||||
|
@ -852,7 +852,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}, openPeer: { [weak self] peerId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil)
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil, nil)
|
||||
}
|
||||
}, openHashtag: { [weak self] peerName, hashtag in
|
||||
if let strongSelf = self {
|
||||
@ -920,7 +920,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
})
|
||||
})))
|
||||
}, openPeer: { [weak self] id, navigation, fromMessage in
|
||||
}, openPeer: { [weak self] id, navigation, fromMessage, _ in
|
||||
self?.openPeer(peerId: id, navigation: navigation, fromMessage: fromMessage)
|
||||
}, openPeerMention: { [weak self] name in
|
||||
self?.openPeerMention(name)
|
||||
@ -1141,7 +1141,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.openPeer(peerId: id, navigation: .default, fromMessage: message)
|
||||
strongSelf.openPeer(peerId: id, navigation: .default, fromMessage: MessageReference(message))
|
||||
})
|
||||
})))
|
||||
|
||||
@ -10963,7 +10963,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case let .mention(peerId, mention):
|
||||
switch action {
|
||||
case .tap:
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil)
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil, nil)
|
||||
case .longTap:
|
||||
strongSelf.controllerInteraction?.longTap(.peerMention(peerId, mention), nil)
|
||||
}
|
||||
@ -11051,7 +11051,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case let .mention(peerId, mention):
|
||||
switch action {
|
||||
case .tap:
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil)
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil, nil)
|
||||
case .longTap:
|
||||
strongSelf.controllerInteraction?.longTap(.peerMention(peerId, mention), nil)
|
||||
}
|
||||
@ -11160,7 +11160,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
case let .mention(peerId, mention):
|
||||
switch action {
|
||||
case .tap:
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil)
|
||||
strongSelf.controllerInteraction?.openPeer(peerId, .default, nil, nil)
|
||||
case .longTap:
|
||||
strongSelf.controllerInteraction?.longTap(.peerMention(peerId, mention), nil)
|
||||
}
|
||||
@ -12978,7 +12978,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
|
||||
private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: Message?, expandAvatar: Bool = false) {
|
||||
private func openPeer(peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer, fromMessage: MessageReference?, expandAvatar: Bool = false) {
|
||||
let _ = self.presentVoiceMessageDiscardAlert(action: {
|
||||
if case let .peer(currentPeerId) = self.chatLocation, peerId == currentPeerId {
|
||||
switch navigation {
|
||||
@ -13008,8 +13008,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
switch navigation {
|
||||
case .info, .default:
|
||||
let peerSignal: Signal<Peer?, NoError>
|
||||
if let fromMessage = fromMessage {
|
||||
peerSignal = loadedPeerFromMessage(account: self.context.account, peerId: peerId, messageId: fromMessage.id)
|
||||
if let messageId = fromMessage?.id {
|
||||
peerSignal = loadedPeerFromMessage(account: self.context.account, peerId: peerId, messageId: messageId)
|
||||
} else {
|
||||
peerSignal = self.context.account.postbox.loadedPeerWithId(peerId) |> map(Optional.init)
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public enum ChatControllerInteractionReaction {
|
||||
|
||||
public final class ChatControllerInteraction {
|
||||
let openMessage: (Message, ChatControllerInteractionOpenMessageMode) -> Bool
|
||||
let openPeer: (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void
|
||||
let openPeer: (PeerId?, ChatControllerInteractionNavigateToPeer, MessageReference?, Peer?) -> Void
|
||||
let openPeerMention: (String) -> Void
|
||||
let openMessageContextMenu: (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void
|
||||
let updateMessageReaction: (Message, ChatControllerInteractionReaction) -> Void
|
||||
@ -152,7 +152,7 @@ public final class ChatControllerInteraction {
|
||||
|
||||
init(
|
||||
openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool,
|
||||
openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void,
|
||||
openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, MessageReference?, Peer?) -> Void,
|
||||
openPeerMention: @escaping (String) -> Void,
|
||||
openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void,
|
||||
openMessageReactionContextMenu: @escaping (Message, ContextExtractedContentContainingNode, ContextGesture?, String) -> Void,
|
||||
@ -327,7 +327,7 @@ public final class ChatControllerInteraction {
|
||||
|
||||
static var `default`: ChatControllerInteraction {
|
||||
return ChatControllerInteraction(openMessage: { _, _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
return false }, openPeer: { _, _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
}, updateMessageReaction: { _, _ in }, activateMessagePinch: { _ in }, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in }, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _ in return false }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
}, presentController: { _, _ in }, presentControllerInCurrent: { _, _ in }, navigationController: {
|
||||
return nil
|
||||
|
@ -1282,14 +1282,14 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.insert(.custom(ChatReadReportContextItem(context: context, message: message, stats: readStats, action: { c, f, stats in
|
||||
if reactionCount == 0, let stats = stats, stats.peers.count == 1 {
|
||||
c.dismiss(completion: {
|
||||
controllerInteraction.openPeer(stats.peers[0].id, .default, nil)
|
||||
controllerInteraction.openPeer(stats.peers[0].id, .default, nil, nil)
|
||||
})
|
||||
} else if (stats != nil && !stats!.peers.isEmpty) || reactionCount != 0 {
|
||||
c.pushItems(items: .single(ContextController.Items(content: .custom(ReactionListContextMenuContent(context: context, availableReactions: availableReactions, message: EngineMessage(message), reaction: nil, readStats: stats, back: { [weak c] in
|
||||
c?.popItems()
|
||||
}, openPeer: { [weak c] id in
|
||||
c?.dismiss(completion: {
|
||||
controllerInteraction.openPeer(id, .default, nil)
|
||||
controllerInteraction.openPeer(id, .default, nil, nil)
|
||||
})
|
||||
})), tip: nil)))
|
||||
} else {
|
||||
|
@ -239,11 +239,7 @@ final class ChatMediaInputMetaSectionItemNode: ListViewItemNode {
|
||||
} else {
|
||||
animatedStickerNode = AnimatedStickerNode()
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
// if let placeholderNode = self.placeholderNode {
|
||||
// self.scalingNode.insertSubnode(animatedStickerNode, belowSubnode: placeholderNode)
|
||||
// } else {
|
||||
self.scalingNode.addSubnode(animatedStickerNode)
|
||||
// }
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: file.resource), width: 128, height: 128, mode: .cached)
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
|
@ -84,7 +84,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
private let scalingNode: ASDisplayNode
|
||||
private let imageNode: TransformImageNode
|
||||
private var animatedStickerNode: AnimatedStickerNode?
|
||||
private var videoStickerNode: VideoStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let highlightNode: ASImageNode
|
||||
private let titleNode: ImmediateTextNode
|
||||
@ -109,7 +109,9 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
didSet {
|
||||
if self.visibilityStatus != oldValue {
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
self.animatedStickerNode?.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
let visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
self.videoNode?.update(isPlaying: visibility)
|
||||
self.animatedStickerNode?.visibility = visibility
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,16 +193,15 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = info.thumbnail {
|
||||
if info.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, info.flags.contains(.isVideo))
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
} else if let item = item {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -225,13 +226,36 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(radius: 6.0), imageSize: imageSize, boundingSize: boundingImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: representation.resource, nilIfEmpty: true))
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, isVideo):
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: boundingImageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: resource, animated: true, nilIfEmpty: true))
|
||||
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = self.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
videoNode = VideoStickerNode()
|
||||
videoNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.videoNode = videoNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.scalingNode.insertSubnode(videoNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.scalingNode.addSubnode(videoNode)
|
||||
}
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
} else {
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
@ -250,6 +274,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
}
|
||||
if let resourceReference = resourceReference {
|
||||
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start())
|
||||
}
|
||||
@ -289,8 +314,9 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = self.imageNode.frame
|
||||
animatedStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let videoNode = self.videoStickerNode {
|
||||
if let videoNode = self.videoNode {
|
||||
videoNode.frame = self.imageNode.frame
|
||||
videoNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.bounds = CGRect(origin: CGPoint(), size: boundingImageSize)
|
||||
@ -338,7 +364,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
}
|
||||
|
||||
override func snapshotForReordering() -> UIView? {
|
||||
if let account = account, let thumbnailItem = self.currentThumbnailItem {
|
||||
if let account = self.account, let thumbnailItem = self.currentThumbnailItem {
|
||||
var imageSize = boundingImageSize
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
let containerNode = ASDisplayNode()
|
||||
@ -348,6 +374,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
|
||||
var snapshotImageNode: TransformImageNode?
|
||||
var snapshotAnimationNode: AnimatedStickerNode?
|
||||
var snapshotVideoNode: VideoStickerNode?
|
||||
switch thumbnailItem {
|
||||
case let .still(representation):
|
||||
imageSize = representation.dimensions.cgSize.aspectFitted(boundingImageSize)
|
||||
@ -359,7 +386,18 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
scalingNode.addSubnode(imageNode)
|
||||
|
||||
snapshotImageNode = imageNode
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, isVideo):
|
||||
if isVideo {
|
||||
let videoNode = VideoStickerNode()
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
scalingNode.addSubnode(videoNode)
|
||||
|
||||
snapshotVideoNode = videoNode
|
||||
} else {
|
||||
let animatedStickerNode = AnimatedStickerNode()
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 128, height: 128, mode: .cached)
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
@ -370,6 +408,7 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
|
||||
snapshotAnimationNode = animatedStickerNode
|
||||
}
|
||||
}
|
||||
|
||||
containerNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedBoundingSize)
|
||||
scalingNode.bounds = CGRect(origin: CGPoint(), size: expandedBoundingSize)
|
||||
@ -388,6 +427,10 @@ final class ChatMediaInputStickerPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = imageFrame
|
||||
animatedStickerNode.updateLayout(size: imageFrame.size)
|
||||
}
|
||||
if let videoStickerNode = snapshotVideoNode {
|
||||
videoStickerNode.frame = imageFrame
|
||||
videoStickerNode.updateLayout(size: imageFrame.size)
|
||||
}
|
||||
|
||||
let expanded = self.currentExpanded
|
||||
let scale = expanded ? 1.0 : boundingImageScale
|
||||
|
@ -1733,7 +1733,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, MessageReference(item.message), item.message.peers[openPeerId])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -3127,7 +3127,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, MessageReference(item.message), item.message.peers[openPeerId])
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -3182,7 +3182,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
}
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
} else if let peer = forwardInfo.source ?? forwardInfo.author {
|
||||
item.controllerInteraction.openPeer(peer.id, peer is TelegramUser ? .info : .chat(textInputState: nil, subject: nil, peekData: nil), nil)
|
||||
item.controllerInteraction.openPeer(peer.id, peer is TelegramUser ? .info : .chat(textInputState: nil, subject: nil, peekData: nil), nil, nil)
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
}
|
||||
@ -3221,7 +3221,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
})
|
||||
case let .peerMention(peerId, _):
|
||||
return .action({
|
||||
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil)
|
||||
self.item?.controllerInteraction.openPeer(peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil, nil)
|
||||
})
|
||||
case let .textMention(name):
|
||||
return .action({
|
||||
|
@ -502,9 +502,9 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
|
||||
self.controllerInteraction.displayMessageTooltip(id, self.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, self.avatarNode.frame)
|
||||
} else {
|
||||
if let channel = self.peer as? TelegramChannel, case .broadcast = channel.info {
|
||||
self.controllerInteraction.openPeer(self.peerId, .chat(textInputState: nil, subject: nil, peekData: nil), nil)
|
||||
self.controllerInteraction.openPeer(self.peerId, .chat(textInputState: nil, subject: nil, peekData: nil), self.messageReference, nil)
|
||||
} else {
|
||||
self.controllerInteraction.openPeer(self.peerId, .info, nil)
|
||||
self.controllerInteraction.openPeer(self.peerId, .info, self.messageReference, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -935,7 +935,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
return
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, MessageReference(item.message), item.message.peers[openPeerId])
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -967,7 +967,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
|
||||
}
|
||||
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
|
||||
} else if let peer = forwardInfo.source ?? forwardInfo.author {
|
||||
item.controllerInteraction.openPeer(peer.id, peer is TelegramUser ? .info : .chat(textInputState: nil, subject: nil, peekData: nil), nil)
|
||||
item.controllerInteraction.openPeer(peer.id, peer is TelegramUser ? .info : .chat(textInputState: nil, subject: nil, peekData: nil), nil, nil)
|
||||
} else if let _ = forwardInfo.authorSignature {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, forwardInfoNode, nil)
|
||||
}
|
||||
|
@ -853,7 +853,7 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
||||
case .setupPoll:
|
||||
break
|
||||
case let .openUserProfile(peerId):
|
||||
item.controllerInteraction.openPeer(peerId, .info, nil)
|
||||
item.controllerInteraction.openPeer(peerId, .info, nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1136,7 +1136,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame)
|
||||
}
|
||||
}
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, item.message)
|
||||
item.controllerInteraction.openPeer(openPeerId, navigate, MessageReference(item.message), item.message.peers[openPeerId])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
|
||||
}
|
||||
item.controllerInteraction.openPeer(id, navigationData, nil)
|
||||
item.controllerInteraction.openPeer(id, navigationData, nil, nil)
|
||||
case let .join(_, joinHash):
|
||||
item.controllerInteraction.openJoinLink(joinHash)
|
||||
}
|
||||
|
@ -247,9 +247,9 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, gallerySource: gallerySource))
|
||||
}
|
||||
return false
|
||||
}, openPeer: { [weak self] peerId, _, message in
|
||||
}, openPeer: { [weak self] peerId, _, message, peer in
|
||||
if let peerId = peerId, peerId != context.account.peerId {
|
||||
self?.openPeer(peerId: peerId, peer: message?.peers[peerId])
|
||||
self?.openPeer(peerId: peerId, peer: peer)
|
||||
}
|
||||
}, openPeerMention: { [weak self] name in
|
||||
self?.openPeerMention(name)
|
||||
|
@ -108,7 +108,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
|
||||
var selectStickerImpl: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?
|
||||
|
||||
self.controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
return false }, openPeer: { _, _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
}, updateMessageReaction: { _, _ in }, activateMessagePinch: { _ in
|
||||
}, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { fileReference, _, _, _, _, node, rect in return selectStickerImpl?(fileReference, node, rect) ?? false }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _ in return false }, requestMessageActionCallback: { _, _, _, _ in }, requestMessageActionUrlAuth: { _, _ in }, activateSwitchInline: { _, _ in }, openUrl: { _, _, _, _ in }, shareCurrentLocation: {}, shareAccountContact: {}, sendBotCommand: { _, _ in }, openInstantPage: { _, _ in }, openWallpaper: { _ in }, openTheme: { _ in }, openHashtag: { _, _ in }, updateInputState: { _ in }, updateInputMode: { _ in }, openMessageShareMenu: { _ in
|
||||
|
@ -88,6 +88,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
private let imageNodeBackground: ASDisplayNode
|
||||
private let imageNode: TransformImageNode
|
||||
private var animationNode: AnimatedStickerNode?
|
||||
private var videoStickerNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private var videoLayer: (SoftwareVideoThumbnailNode, SoftwareVideoLayerFrameManager, SampleBufferLayer)?
|
||||
private var currentImageResource: TelegramMediaResource?
|
||||
@ -416,7 +417,15 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
animationNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let videoStickerNode = strongSelf.videoStickerNode {
|
||||
strongSelf.videoStickerNode = nil
|
||||
videoStickerNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
if let animatedStickerFile = animatedStickerFile {
|
||||
if animatedStickerFile.isVideoSticker {
|
||||
|
||||
} else {
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let currentAnimationNode = strongSelf.animationNode {
|
||||
animationNode = currentAnimationNode
|
||||
@ -440,6 +449,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: animatedStickerFile.resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let progressSize = CGSize(width: 24.0, height: 24.0)
|
||||
let progressFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((nodeLayout.contentSize.width - progressSize.width) / 2.0), y: floorToScreenPixels((nodeLayout.contentSize.height - progressSize.height) / 2.0)), size: progressSize)
|
||||
|
@ -132,7 +132,9 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
func setup(account: Account, item: HorizontalStickerGridItem) {
|
||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1.file.id != item.file.id {
|
||||
if let dimensions = item.file.dimensions {
|
||||
if item.file.isAnimatedSticker {
|
||||
if item.file.isVideoSticker {
|
||||
|
||||
} else if item.file.isAnimatedSticker {
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let currentAnimationNode = self.animationNode {
|
||||
animationNode = currentAnimationNode
|
||||
|
@ -115,7 +115,9 @@ final class TrendingTopItemNode: ASDisplayNode {
|
||||
self.file = item.file
|
||||
self.itemSize = itemSize
|
||||
|
||||
if item.file.isAnimatedSticker {
|
||||
if item.file.isVideoSticker {
|
||||
|
||||
} else if item.file.isAnimatedSticker {
|
||||
let animationNode: AnimatedStickerNode
|
||||
if let currentAnimationNode = self.animationNode {
|
||||
animationNode = currentAnimationNode
|
||||
|
@ -66,7 +66,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}, openPeer: { _, _, _ in
|
||||
}, openPeer: { _, _, _, _ in
|
||||
}, openPeerMention: { _ in
|
||||
}, openMessageContextMenu: { _, _, _, _, _ in
|
||||
}, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
|
@ -79,7 +79,15 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
|
||||
var status: Signal<PeerInfoStatusData?, NoError> {
|
||||
return .single(nil)
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
return self.groupsInCommonContext.state
|
||||
|> map { state in
|
||||
if let count = state.count {
|
||||
return PeerInfoStatusData(text: presentationData.strings.SharedMedia_CommonGroupCount(Int32(count)), isActivity: false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tabBarOffsetUpdated: ((ContainedViewLayoutTransition) -> Void)?
|
||||
@ -178,7 +186,7 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
}
|
||||
}
|
||||
let transaction = preparedTransition(from: self.currentEntries, to: entries, context: self.context, presentationData: presentationData, openPeer: { [weak self] peer in
|
||||
self?.chatControllerInteraction.openPeer(peer.id, .default, nil)
|
||||
self?.chatControllerInteraction.openPeer(peer.id, .default, nil, nil)
|
||||
}, openPeerContextAction: { [weak self] peer, node, gesture in
|
||||
self?.openPeerContextAction(peer, node, gesture)
|
||||
})
|
||||
|
@ -446,7 +446,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
}
|
||||
}
|
||||
|
||||
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, ignoreGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?) -> Signal<PeerInfoScreenData, NoError> {
|
||||
func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, isSettings: Bool, hintGroupInCommon: PeerId?, existingRequestsContext: PeerInvitationImportersContext?) -> Signal<PeerInfoScreenData, NoError> {
|
||||
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: isSettings)
|
||||
|> mapToSignal { inputData -> Signal<PeerInfoScreenData, NoError> in
|
||||
switch inputData {
|
||||
@ -471,7 +471,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
case let .user(userPeerId, secretChatId, kind):
|
||||
let groupsInCommon: GroupsInCommonContext?
|
||||
if [.user, .bot].contains(kind) {
|
||||
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: userPeerId)
|
||||
groupsInCommon = GroupsInCommonContext(account: context.account, peerId: userPeerId, hintGroupInCommon: hintGroupInCommon)
|
||||
} else {
|
||||
groupsInCommon = nil
|
||||
}
|
||||
@ -590,7 +590,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
|
||||
if cachedData.commonGroupCount != 0 {
|
||||
availablePanes?.append(.groupsInCommon)
|
||||
} else if hintGroupInCommon != nil {
|
||||
availablePanes?.append(.groupsInCommon)
|
||||
}
|
||||
} else if hintGroupInCommon != nil {
|
||||
availablePanes = [.groupsInCommon]
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
|
@ -468,6 +468,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
||||
|
||||
private(set) var currentPaneKey: PeerInfoPaneKey?
|
||||
var pendingSwitchToPaneKey: PeerInfoPaneKey?
|
||||
var expandOnSwitch = false
|
||||
|
||||
var currentPane: PeerInfoPaneWrapper? {
|
||||
if let currentPaneKey = self.currentPaneKey {
|
||||
@ -550,6 +551,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
||||
}
|
||||
} else if strongSelf.pendingSwitchToPaneKey != key {
|
||||
strongSelf.pendingSwitchToPaneKey = key
|
||||
strongSelf.expandOnSwitch = true
|
||||
|
||||
if let (size, sideInset, bottomInset, visibleHeight, expansionFraction, presentationData, data) = strongSelf.currentParams {
|
||||
strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, visibleHeight: visibleHeight, expansionFraction: expansionFraction, presentationData: presentationData, data: data, transition: .animated(duration: 0.4, curve: .spring))
|
||||
@ -967,7 +969,8 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, UIGestureRecognizerDelegat
|
||||
}
|
||||
}
|
||||
if let previousCurrentPaneKey = previousCurrentPaneKey, self.currentPaneKey != previousCurrentPaneKey {
|
||||
self.currentPaneUpdated?(true)
|
||||
self.currentPaneUpdated?(self.expandOnSwitch)
|
||||
self.expandOnSwitch = false
|
||||
}
|
||||
if updateCurrentPaneStatus {
|
||||
self.currentPaneStatusPromise.set(self.currentPane?.node.status ?? .single(nil))
|
||||
|
@ -1607,7 +1607,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
private var didSetReady = false
|
||||
|
||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, callMessages: [Message], isSettings: Bool, ignoreGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?) {
|
||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, callMessages: [Message], isSettings: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
@ -1758,7 +1758,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
return false
|
||||
}
|
||||
return strongSelf.openMessage(id: message.id)
|
||||
}, openPeer: { [weak self] id, navigation, _ in
|
||||
}, openPeer: { [weak self] id, navigation, _, _ in
|
||||
if let id = id {
|
||||
self?.openPeer(peerId: id, navigation: navigation)
|
||||
}
|
||||
@ -2285,7 +2285,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let items: [ContextMenuItem] = [
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_LinkDialogOpen, icon: { _ in nil }, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
self?.chatInterfaceInteraction.openPeer(peer.id, .default, nil)
|
||||
self?.chatInterfaceInteraction.openPeer(peer.id, .default, nil, nil)
|
||||
}))
|
||||
]
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
@ -2893,7 +2893,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}))
|
||||
}
|
||||
} else {
|
||||
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, ignoreGroupInCommon: ignoreGroupInCommon, existingRequestsContext: requestsContext)
|
||||
screenData = peerInfoScreenData(context: context, peerId: peerId, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, isSettings: self.isSettings, hintGroupInCommon: hintGroupInCommon, existingRequestsContext: requestsContext)
|
||||
|
||||
self.headerNode.displayAvatarContextMenu = { [weak self] node, gesture in
|
||||
guard let strongSelf = self, let peer = strongSelf.data?.peer else {
|
||||
@ -7001,7 +7001,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
|
||||
private let nearbyPeerDistance: Int32?
|
||||
private let callMessages: [Message]
|
||||
private let isSettings: Bool
|
||||
private let ignoreGroupInCommon: PeerId?
|
||||
private let hintGroupInCommon: PeerId?
|
||||
private weak var requestsContext: PeerInvitationImportersContext?
|
||||
|
||||
fileprivate var presentationData: PresentationData
|
||||
@ -7027,7 +7027,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, callMessages: [Message], isSettings: Bool = false, ignoreGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.peerId = peerId
|
||||
@ -7036,7 +7036,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
|
||||
self.nearbyPeerDistance = nearbyPeerDistance
|
||||
self.callMessages = callMessages
|
||||
self.isSettings = isSettings
|
||||
self.ignoreGroupInCommon = ignoreGroupInCommon
|
||||
self.hintGroupInCommon = hintGroupInCommon
|
||||
self.requestsContext = requestsContext
|
||||
|
||||
self.presentationData = updatedPresentationData?.0 ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -7324,7 +7324,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, callMessages: self.callMessages, isSettings: self.isSettings, ignoreGroupInCommon: self.ignoreGroupInCommon, requestsContext: requestsContext)
|
||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, callMessages: self.callMessages, isSettings: self.isSettings, hintGroupInCommon: self.hintGroupInCommon, requestsContext: requestsContext)
|
||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||
|
@ -1239,7 +1239,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
let controllerInteraction: ChatControllerInteraction
|
||||
|
||||
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||
return false }, openPeer: { _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
return false }, openPeer: { _, _, _, _ in }, openPeerMention: { _ in }, openMessageContextMenu: { _, _, _, _, _ in }, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
}, updateMessageReaction: { _, _ in }, activateMessagePinch: { _ in
|
||||
}, openMessageContextActions: { _, _, _, _ in }, navigateToMessage: { _, _ in }, navigateToMessageStandalone: { _ in
|
||||
}, tapMessage: { message in
|
||||
@ -1437,7 +1437,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
||||
} else if peer is TelegramUser {
|
||||
var nearbyPeerDistance: Int32?
|
||||
var callMessages: [Message] = []
|
||||
var ignoreGroupInCommon: PeerId?
|
||||
var hintGroupInCommon: PeerId?
|
||||
switch mode {
|
||||
case let .nearbyPeer(distance):
|
||||
nearbyPeerDistance = distance
|
||||
@ -1446,9 +1446,9 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
||||
case .generic:
|
||||
break
|
||||
case let .group(id):
|
||||
ignoreGroupInCommon = id
|
||||
hintGroupInCommon = id
|
||||
}
|
||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, callMessages: callMessages, ignoreGroupInCommon: ignoreGroupInCommon)
|
||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, callMessages: callMessages, hintGroupInCommon: hintGroupInCommon)
|
||||
} else if peer is TelegramSecretChat {
|
||||
return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, callMessages: [])
|
||||
}
|
||||
|
@ -156,7 +156,9 @@ final class StickerPaneSearchStickerItemNode: GridItemNode {
|
||||
self.textNode.attributedText = NSAttributedString(string: code ?? "", font: textFont, textColor: .black)
|
||||
|
||||
if let dimensions = stickerItem.file.dimensions {
|
||||
if stickerItem.file.isAnimatedSticker {
|
||||
if stickerItem.file.isVideoSticker {
|
||||
|
||||
} else if stickerItem.file.isAnimatedSticker {
|
||||
if self.animationNode == nil {
|
||||
let animationNode = AnimatedStickerNode()
|
||||
animationNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.imageNodeTap(_:))))
|
||||
|
@ -12,6 +12,7 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ShimmerEffect
|
||||
import MergeLists
|
||||
import SoftwareVideo
|
||||
|
||||
private let boundingSize = CGSize(width: 41.0, height: 41.0)
|
||||
private let boundingImageSize = CGSize(width: 28.0, height: 28.0)
|
||||
@ -154,6 +155,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
private let containerNode: ASDisplayNode
|
||||
private let imageNode: TransformImageNode
|
||||
private var animatedStickerNode: AnimatedStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var placeholderNode: StickerShimmerEffectNode?
|
||||
private let unreadNode: ASImageNode
|
||||
|
||||
@ -255,16 +257,16 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
if let thumbnail = info.thumbnail {
|
||||
if info.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions)
|
||||
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(thumbnail.resource, thumbnail.dimensions, info.flags.contains(.isVideo))
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
} else if let item = item {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(item.file.resource, item.file.dimensions ?? PixelDimensions(width: 100, height: 100), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -284,13 +286,36 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: representation.resource, nilIfEmpty: true))
|
||||
case let .animated(resource, _):
|
||||
case let .animated(resource, _, isVideo):
|
||||
let imageApply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))
|
||||
imageApply()
|
||||
self.imageNode.setSignal(chatMessageStickerPackThumbnail(postbox: account.postbox, resource: resource, animated: true, nilIfEmpty: true))
|
||||
|
||||
let loopAnimatedStickers = self.inputNodeInteraction?.stickerSettings?.loopAnimatedStickers ?? false
|
||||
|
||||
if isVideo {
|
||||
let videoNode: VideoStickerNode
|
||||
if let current = self.videoNode {
|
||||
videoNode = current
|
||||
} else {
|
||||
videoNode = VideoStickerNode()
|
||||
videoNode.started = { [weak self] in
|
||||
self?.imageNode.isHidden = true
|
||||
}
|
||||
self.videoNode = videoNode
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
self.containerNode.insertSubnode(videoNode, belowSubnode: placeholderNode)
|
||||
} else {
|
||||
self.containerNode.addSubnode(videoNode)
|
||||
}
|
||||
|
||||
if let resource = resource as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
}
|
||||
videoNode.update(isPlaying: self.visibilityStatus && loopAnimatedStickers)
|
||||
} else {
|
||||
let animatedStickerNode: AnimatedStickerNode
|
||||
if let current = self.animatedStickerNode {
|
||||
animatedStickerNode = current
|
||||
@ -309,6 +334,7 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
}
|
||||
animatedStickerNode.visibility = self.visibilityStatus && loopAnimatedStickers
|
||||
}
|
||||
}
|
||||
if let resourceReference = resourceReference {
|
||||
self.stickerFetchedDisposable.set(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: resourceReference).start())
|
||||
}
|
||||
@ -328,6 +354,10 @@ private final class FeaturedPackItemNode: ListViewItemNode {
|
||||
animatedStickerNode.frame = self.imageNode.frame
|
||||
animatedStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let videoStickerNode = self.videoNode {
|
||||
videoStickerNode.frame = self.imageNode.frame
|
||||
videoStickerNode.updateLayout(size: self.imageNode.frame.size)
|
||||
}
|
||||
if let placeholderNode = self.placeholderNode {
|
||||
placeholderNode.bounds = CGRect(origin: CGPoint(), size: boundingImageSize)
|
||||
placeholderNode.position = self.imageNode.position
|
||||
|
@ -26,6 +26,7 @@ swift_library(
|
||||
"//submodules/SlotMachineAnimationNode:SlotMachineAnimationNode",
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/SoftwareVideo:SoftwareVideo",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -4,6 +4,7 @@ import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
@ -16,6 +17,7 @@ import AnimationUI
|
||||
import StickerResources
|
||||
import AvatarNode
|
||||
import AccountContext
|
||||
import SoftwareVideo
|
||||
|
||||
final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let elevatedLayout: Bool
|
||||
@ -26,6 +28,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let iconCheckNode: RadialStatusNode?
|
||||
private let animationNode: AnimationNode?
|
||||
private var animatedStickerNode: AnimatedStickerNode?
|
||||
private var videoNode: VideoStickerNode?
|
||||
private var slotMachineNode: SlotMachineAnimationNode?
|
||||
private var stillStickerNode: TransformImageNode?
|
||||
private var stickerImageSize: CGSize?
|
||||
@ -92,6 +95,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = nil
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = true
|
||||
self.originalRemainingSeconds = 5
|
||||
@ -112,6 +116,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
}
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = undo
|
||||
@ -122,6 +127,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_archiveswipe", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = undo
|
||||
@ -132,6 +138,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = undo
|
||||
@ -142,6 +149,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: isOn ? "anim_autoremove_on" : "anim_autoremove_off", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
if let title = title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
}
|
||||
@ -154,6 +162,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -168,6 +177,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -182,6 +192,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
undoTextColor = UIColor(rgb: 0xff7b74)
|
||||
|
||||
@ -200,6 +211,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_linkcopied", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -214,6 +226,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_banned", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -231,6 +244,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = nil
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 5
|
||||
@ -240,6 +254,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let formattedString = presentationData.strings.ChatList_AddedToFolderTooltip(chatTitle, folderTitle)
|
||||
|
||||
@ -257,7 +272,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
|
||||
self.videoNode = nil
|
||||
self.videoNode = nil
|
||||
let formattedString = presentationData.strings.ChatList_RemovedFromFolderTooltip(chatTitle, folderTitle)
|
||||
|
||||
let string = NSMutableAttributedString(attributedString: NSAttributedString(string: formattedString.string, font: Font.regular(14.0), textColor: .white))
|
||||
@ -274,6 +290,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_payment", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let formattedString = presentationData.strings.Checkout_SuccessfulTooltip(currencyValue, itemTitle)
|
||||
|
||||
@ -291,6 +308,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: isHidden ? "anim_message_hidepin" : "anim_message_unpin", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -325,6 +343,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_swipereply", colors: [:], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
self.textNode.maximumNumberOfLines = 2
|
||||
@ -342,23 +361,22 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
|
||||
enum StickerPackThumbnailItem {
|
||||
case still(TelegramMediaImageRepresentation)
|
||||
case animated(EngineMediaResource)
|
||||
case animated(EngineMediaResource, Bool)
|
||||
}
|
||||
|
||||
var thumbnailItem: StickerPackThumbnailItem?
|
||||
var resourceReference: MediaResourceReference?
|
||||
|
||||
if let thumbnail = info.thumbnail {
|
||||
if info.flags.contains(.isAnimated) {
|
||||
thumbnailItem = .animated(EngineMediaResource(thumbnail.resource))
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
if info.flags.contains(.isAnimated) || info.flags.contains(.isVideo) {
|
||||
thumbnailItem = .animated(EngineMediaResource(thumbnail.resource), info.flags.contains(.isVideo))
|
||||
} else {
|
||||
thumbnailItem = .still(thumbnail)
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
}
|
||||
resourceReference = MediaResourceReference.stickerPackThumbnail(stickerPack: .id(id: info.id.id, accessHash: info.accessHash), resource: thumbnail.resource)
|
||||
} else if let item = topItem {
|
||||
if item.file.isAnimatedSticker {
|
||||
thumbnailItem = .animated(EngineMediaResource(item.file.resource))
|
||||
if item.file.isAnimatedSticker || item.file.isVideoSticker {
|
||||
thumbnailItem = .animated(EngineMediaResource(item.file.resource), item.file.isVideoSticker)
|
||||
resourceReference = MediaResourceReference.media(media: .standalone(media: item.file), resource: item.file.resource)
|
||||
} else if let dimensions = item.file.dimensions, let resource = chatMessageStickerResource(file: item.file, small: true) as? TelegramMediaResource {
|
||||
thumbnailItem = .still(TelegramMediaImageRepresentation(dimensions: dimensions, resource: resource, progressiveSizes: [], immediateThumbnailData: nil))
|
||||
@ -378,7 +396,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.stickerImageSize = stillImageSize
|
||||
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: representation.resource)
|
||||
case let .animated(resource):
|
||||
case let .animated(resource, _):
|
||||
self.stickerImageSize = imageBoundingSize
|
||||
|
||||
updatedImageSignal = chatMessageStickerPackThumbnail(postbox: context.account.postbox, resource: resource._asResource(), animated: true)
|
||||
@ -416,12 +434,22 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
switch thumbnailItem {
|
||||
case .still:
|
||||
break
|
||||
case let .animated(resource):
|
||||
case let .animated(resource, isVideo):
|
||||
if isVideo {
|
||||
let videoNode = VideoStickerNode()
|
||||
self.videoNode = videoNode
|
||||
|
||||
if let resource = resource._asResource() as? TelegramMediaResource {
|
||||
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
|
||||
videoNode.update(account: context.account, fileReference: .standalone(media: dummyFile))
|
||||
}
|
||||
} else {
|
||||
let animatedStickerNode = AnimatedStickerNode()
|
||||
self.animatedStickerNode = animatedStickerNode
|
||||
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: resource._asResource()), width: 80, height: 80, mode: .cached)
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .dice(dice, context, text, action):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
@ -482,6 +510,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: cancelled ? "anim_proximity_cancelled" : "anim_proximity_set", colors: [:], scale: 0.45)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -500,6 +529,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = nil
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -517,6 +547,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: slowdown ? "anim_voicespeedstop" : "anim_voicespeed", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -532,6 +563,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: savedMessages ? "anim_savedmessages" : "anim_forward", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -547,6 +579,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_gigagroup", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -562,6 +595,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_linkrevoked", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -577,6 +611,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_vcrecord", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -592,6 +627,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_vcflag", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -607,6 +643,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_vcspeak", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -704,6 +741,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_copy", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
@ -739,6 +777,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_inviterequest", colors: [:], scale: 0.066)
|
||||
self.animatedStickerNode = nil
|
||||
self.videoNode = nil
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
|
||||
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
|
||||
self.textNode.maximumNumberOfLines = 2
|
||||
@ -785,6 +824,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.animationNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.stillStickerNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.videoNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.panelWrapperNode.addSubnode(self.titleNode)
|
||||
@ -814,6 +854,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.animatedStickerNode?.started = { [weak self] in
|
||||
self?.stillStickerNode?.isHidden = true
|
||||
}
|
||||
self.videoNode?.started = { [weak self] in
|
||||
self?.stillStickerNode?.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -998,12 +1041,20 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
transition.updateFrame(node: stillStickerNode, frame: iconFrame)
|
||||
}
|
||||
|
||||
if let animatedStickerNode = self.animatedStickerNode {
|
||||
if let videoNode = self.videoNode {
|
||||
videoNode.updateLayout(size: iconFrame.size)
|
||||
transition.updateFrame(node: videoNode, frame: iconFrame)
|
||||
} else if let animatedStickerNode = self.animatedStickerNode {
|
||||
animatedStickerNode.updateLayout(size: iconFrame.size)
|
||||
transition.updateFrame(node: animatedStickerNode, frame: iconFrame)
|
||||
} else if let slotMachineNode = self.slotMachineNode {
|
||||
transition.updateFrame(node: slotMachineNode, frame: iconFrame)
|
||||
}
|
||||
} else if let videoNode = self.videoNode {
|
||||
let iconSize = CGSize(width: 32.0, height: 32.0)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
|
||||
videoNode.updateLayout(size: iconFrame.size)
|
||||
transition.updateFrame(node: videoNode, frame: iconFrame)
|
||||
} else if let animatedStickerNode = self.animatedStickerNode {
|
||||
let iconSize = CGSize(width: 32.0, height: 32.0)
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
|
||||
@ -1054,6 +1105,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
})
|
||||
}
|
||||
|
||||
self.videoNode?.update(isPlaying: true)
|
||||
self.animatedStickerNode?.visibility = true
|
||||
|
||||
self.checkTimer()
|
||||
|
Loading…
x
Reference in New Issue
Block a user