diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/BUILD index 8637dac9eb..0b5beda6f2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/BUILD @@ -43,6 +43,7 @@ swift_library( "//submodules/ComponentFlow", "//submodules/TelegramUI/Components/PlainButtonComponent", "//submodules/Components/BundleIconComponent", + "//submodules/TelegramUI/Components/EmojiTextAttachmentView", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift index 376bd60be9..bcbbe51e91 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift @@ -32,6 +32,7 @@ import MessageInlineBlockBackgroundView import ComponentFlow import PlainButtonComponent import AvatarNode +import EmojiTextAttachmentView public enum ChatMessageAttachedContentActionIcon { case instant @@ -53,6 +54,7 @@ public struct ChatMessageAttachedContentNodeMediaFlags: OptionSet { public static let preferMediaBeforeText = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 1) public static let preferMediaAspectFilled = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 2) public static let titleBeforeMedia = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 3) + public static let stickerPack = ChatMessageAttachedContentNodeMediaFlags(rawValue: 1 << 3) } public final class ChatMessageAttachedContentNode: ASDisplayNode { @@ -98,6 +100,8 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { private var closeButton: ComponentView? private var closeButtonImage: UIImage? + private var inlineStickerLayers: [InlineStickerItemLayer] = [] + private var inlineMediaValue: InlineMedia? //private var additionalImageBadgeNode: ChatMessageInteractiveMediaBadge? @@ -129,6 +133,8 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { self.contentMedia?.visibility = self.visibility != .none self.contentInstantVideo?.visibility = self.visibility != .none + self.inlineStickerLayers.forEach({ $0.isVisibleForAnimations = self.visibility != .none }) + switch self.visibility { case .none: self.text?.visibilityRect = nil @@ -296,6 +302,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { var contentMediaValue: Media? var contentFileValue: TelegramMediaFile? + var contentAnimatedFilesValue: [TelegramMediaFile] = [] var contentMediaAutomaticPlayback: Bool = false var contentMediaAutomaticDownload: InteractiveMediaNodeAutodownloadMode = .none @@ -317,8 +324,11 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { if let (mediaArray, flags) = mediaAndFlags { contentMediaInline = flags.contains(.preferMediaInline) - - if let media = mediaArray.first { + + if flags.contains(.stickerPack), let files = mediaArray as? [TelegramMediaFile], let file = files.first { + contentMediaValue = file + contentAnimatedFilesValue = files + } else if let media = mediaArray.first { if let file = media as? TelegramMediaFile { if file.mimeType == "application/x-tgtheme-ios", let size = file.size, size < 16 * 1024 { contentMediaValue = file @@ -950,7 +960,52 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { let backgroundFrame = CGRect(origin: CGPoint(x: backgroundInsets.left, y: backgroundInsets.top), size: CGSize(width: actualSize.width - backgroundInsets.left - backgroundInsets.right, height: actualSize.height - backgroundInsets.top - backgroundInsets.bottom)) var patternTopRightPosition = CGPoint() - if let (inlineMediaValue, inlineMediaSize) = inlineMediaAndSize { + if !contentAnimatedFilesValue.isEmpty, let (_, inlineMediaSize) = inlineMediaAndSize { + var inlineMediaFrame = CGRect(origin: CGPoint(x: actualSize.width - insets.right - inlineMediaSize.width, y: backgroundInsets.top + inlineMediaEdgeInset), size: inlineMediaSize) + if contentLayoutOrder.isEmpty { + inlineMediaFrame.origin.x = insets.left + } + + patternTopRightPosition.x = insets.right + inlineMediaSize.width - 6.0 + + if !contentAnimatedFilesValue.isEmpty { + if contentAnimatedFilesValue.count < 4, let file = contentAnimatedFilesValue.first { + let stickerLayer: InlineStickerItemLayer + if self.inlineStickerLayers.count == 1, let current = self.inlineStickerLayers.first, current.file?.isEqual(to: file) == true { + stickerLayer = current + } else { + self.inlineStickerLayers.forEach({ $0.removeFromSuperlayer() }) + stickerLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file, custom: nil), file: file, cache: controllerInteraction.presentationContext.animationCache, renderer: controllerInteraction.presentationContext.animationRenderer, placeholderColor: mainColor.withMultipliedAlpha(0.1), pointSize: CGSize(width: 64.0, height: 64.0), dynamicColor: nil) + self.transformContainer.layer.addSublayer(stickerLayer) + + self.inlineStickerLayers = [stickerLayer] + } + stickerLayer.isVisibleForAnimations = self.visibility != .none + stickerLayer.frame = inlineMediaFrame + } else if contentAnimatedFilesValue.count == 4 { + var stickerLayers: [InlineStickerItemLayer] = [] + if self.inlineStickerLayers.count == contentAnimatedFilesValue.count { + stickerLayers = self.inlineStickerLayers + } else { + for file in contentAnimatedFilesValue { + let stickerLayer = InlineStickerItemLayer(context: context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file, custom: nil), file: file, cache: controllerInteraction.presentationContext.animationCache, renderer: controllerInteraction.presentationContext.animationRenderer, placeholderColor: mainColor.withMultipliedAlpha(0.1), pointSize: CGSize(width: 64.0, height: 64.0), dynamicColor: nil) + self.transformContainer.layer.addSublayer(stickerLayer) + stickerLayers.append(stickerLayer) + } + self.inlineStickerLayers = stickerLayers + } + var frames: [CGRect] = [] + let smallSize = CGSize(width: inlineMediaFrame.width / 2.0, height: inlineMediaFrame.width / 2.0) + frames.append(CGRect(origin: inlineMediaFrame.origin, size: smallSize)) + frames.append(CGRect(origin: inlineMediaFrame.origin.offsetBy(dx: smallSize.width, dy: 0.0), size: smallSize)) + frames.append(CGRect(origin: inlineMediaFrame.origin.offsetBy(dx: 0.0, dy: smallSize.height), size: smallSize)) + frames.append(CGRect(origin: inlineMediaFrame.origin.offsetBy(dx: smallSize.width, dy: smallSize.height), size: smallSize)) + for i in 0 ..< stickerLayers.count { + stickerLayers[i].frame = frames[i] + } + } + } + } else if let (inlineMediaValue, inlineMediaSize) = inlineMediaAndSize { var inlineMediaFrame = CGRect(origin: CGPoint(x: actualSize.width - insets.right - inlineMediaSize.width, y: backgroundInsets.top + inlineMediaEdgeInset), size: inlineMediaSize) if contentLayoutOrder.isEmpty { inlineMediaFrame.origin.x = insets.left diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift index d0c6cec2db..cf5f1c7dcc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -481,7 +481,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent } for attribute in webpage.attributes { if case let .stickerPack(stickerPack) = attribute, !stickerPack.files.isEmpty { - mediaAndFlags = (stickerPack.files, .preferMediaInline) + mediaAndFlags = (stickerPack.files, [.preferMediaInline, .stickerPack]) break } } diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift index a35d388009..ea9f67a45b 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/StickerCutoutOutlineView.swift @@ -254,20 +254,18 @@ private func findContours(pixelBuffer: CVPixelBuffer) -> [CGPoint] { repeat { var found = false for i in 0 ..< 8 { - for j in 1 ..< 2 { - let direction = (previousDirection + i) % 8 - let newX = currentPoint.x + dx[direction] * j - let newY = currentPoint.y + dy[direction] * j - let newPoint = Point(x: newX, y: newY) - - if isBlackPixel(newPoint) && !(visited[newPoint] == true) { - contour.append(newPoint) - previousDirection = (direction + 5) % 8 - currentPoint = newPoint - found = true - markVisited(newPoint) - break - } + let direction = (previousDirection + i) % 8 + let newX = currentPoint.x + dx[direction] + let newY = currentPoint.y + dy[direction] + let newPoint = Point(x: newX, y: newY) + + if isBlackPixel(newPoint) && !(visited[newPoint] == true) { + contour.append(newPoint) + previousDirection = (direction + 5) % 8 + currentPoint = newPoint + found = true + markVisited(newPoint) + break } } if !found {