Gift web preview

This commit is contained in:
Ilya Laktyushin 2025-01-07 20:34:57 +04:00
parent 7f34671792
commit 2bf24b2bd9
7 changed files with 106 additions and 9 deletions

View File

@ -315,7 +315,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
var mediaAndFlags = mediaAndFlags
if let mediaAndFlagsValue = mediaAndFlags {
if mediaAndFlagsValue.0.first is TelegramMediaStory || mediaAndFlagsValue.0.first is WallpaperPreviewMedia {
if mediaAndFlagsValue.0.first is TelegramMediaStory || mediaAndFlagsValue.0.first is WallpaperPreviewMedia || mediaAndFlagsValue.0.first is UniqueGiftPreviewMedia {
var flags = mediaAndFlagsValue.1
flags.remove(.preferMediaInline)
mediaAndFlags = (mediaAndFlagsValue.0, flags)
@ -374,13 +374,15 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
contentMediaAspectFilled = true
}
}
} else if let _ = media as? TelegramMediaImage {
} else if media is TelegramMediaImage {
contentMediaValue = media
} else if let _ = media as? TelegramMediaWebFile {
} else if media is TelegramMediaWebFile {
contentMediaValue = media
} else if let _ = media as? WallpaperPreviewMedia {
} else if media is WallpaperPreviewMedia {
contentMediaValue = media
} else if let _ = media as? TelegramMediaStory {
} else if media is TelegramMediaStory {
contentMediaValue = media
} else if media is UniqueGiftPreviewMedia {
contentMediaValue = media
}
}

View File

@ -1093,7 +1093,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
subject: .custom(uniqueBackgroundColor, uniqueSecondBackgroundColor, uniquePatternColor, uniquePatternFile.fileId.id),
files: files,
isDark: false,
avatarCenter: CGPoint(x: patternSize.width / 2.0, y: 106.0),
avatarCenter: CGPoint(x: patternSize.width / 2.0, y: 104.0),
avatarScale: 1.0,
defaultHeight: patternSize.height,
avatarTransitionFraction: 0.0,

View File

@ -14,6 +14,7 @@ swift_library(
"//submodules/Postbox",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Display",
"//submodules/ComponentFlow",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
@ -40,6 +41,7 @@ swift_library(
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
"//submodules/TelegramUI/Components/WallpaperPreviewMedia",
"//submodules/TelegramUI/Components/TextNodeWithEntities",
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
"//submodules/Utils/RangeSet",
],
visibility = [

View File

@ -4,6 +4,7 @@ import AsyncDisplayKit
import Postbox
import SwiftSignalKit
import Display
import ComponentFlow
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
@ -31,6 +32,7 @@ import ChatMessageItemCommon
import WallpaperPreviewMedia
import TextNodeWithEntities
import RangeSet
import GiftItemComponent
private struct FetchControls {
let fetch: (Bool) -> Void
@ -433,6 +435,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
private var videoNode: UniversalVideoNode?
private var videoContent: UniversalVideoContent?
private var animatedStickerNode: AnimatedStickerNode?
private var giftView: ComponentView<Empty>?
private var statusNode: RadialStatusNode?
public var videoNodeDecoration: ChatBubbleVideoDecoration?
public var decoration: UniversalVideoDecoration? {
@ -833,6 +836,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
var maxDimensions = layoutConstants.image.maxDimensions
var maxHeight = layoutConstants.image.maxDimensions.height
var isStory = false
var isGift = false
let _ = isStory
@ -907,6 +911,9 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
case .color, .gradient, .emoticon:
unboundSize = CGSize(width: 128.0, height: 128.0)
}
} else if let _ = media as? UniqueGiftPreviewMedia {
isGift = true
unboundSize = CGSize(width: 200.0, height: 200.0)
} else {
var extendedMedia: TelegramExtendedMedia?
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
@ -960,7 +967,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
switch sizeCalculation {
case let .constrained(constrainedSize):
if isSticker {
if isSticker || isGift {
nativeSize = unboundSize.aspectFittedOrSmaller(constrainedSize)
} else {
var constrainedSize = constrainedSize
@ -1691,6 +1698,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
case .themeSettings, .color, .gradient, .image, .emoticon:
updatedStatusSignal = .single((.Local, nil))
}
} else if let _ = media as? UniqueGiftPreviewMedia {
updatedStatusSignal = .single((.Local, nil))
}
}
@ -1887,7 +1896,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}
}
if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }), strongSelf.extendedMediaOverlayNode == nil {
strongSelf.internallyVisible = false
}
@ -1924,6 +1932,40 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
animatedStickerNode.updateLayout(size: imageFrame.size)
}
if let giftPreview = media as? UniqueGiftPreviewMedia, let gift = giftPreview.content {
let giftView: ComponentView<Empty>
if let current = strongSelf.giftView {
giftView = current
} else {
giftView = ComponentView()
strongSelf.giftView = giftView
}
let _ = giftView.update(
transition: .immediate,
component: AnyComponent(
GiftItemComponent(
context: context,
theme: presentationData.theme.theme,
subject: .uniqueGift(gift: gift),
mode: .preview
)
),
environment: {},
containerSize: imageFrame.size
)
if let giftView = giftView.view {
if giftView.superview == nil {
strongSelf.pinchContainerNode.contentNode.view.addSubview(giftView)
}
giftView.frame = imageFrame
}
} else if let giftView = strongSelf.giftView {
strongSelf.giftView = nil
giftView.view?.removeFromSuperview()
}
if let updateImageSignal = updateImageSignal {
strongSelf.imageNode.captureProtected = message.isCopyProtected() || isExtendedMedia
strongSelf.imageNode.setSignal(updateImageSignal(synchronousLoads, false), attemptSynchronously: synchronousLoads)

View File

@ -380,6 +380,14 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
let media = WallpaperPreviewMedia(content: .themeSettings(settings))
mediaAndFlags = ([media], ChatMessageAttachedContentNodeMediaFlags())
}
} else if type == "telegram_nft" {
for attribute in webpage.attributes {
if case let .starGift(gift) = attribute, case let .unique(uniqueGift) = gift.gift {
let media = UniqueGiftPreviewMedia(content: uniqueGift)
mediaAndFlags = ([media], [])
break
}
}
}
}
@ -459,6 +467,8 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
actionTitle = isEmoji ? item.presentationData.strings.Conversation_ViewEmojis : item.presentationData.strings.Conversation_ViewStickers
case "telegram_nft":
actionTitle = item.presentationData.strings.Conversation_ViewStarGift
text = nil
entities = nil
default:
break
}

View File

@ -80,6 +80,7 @@ public final class GiftItemComponent: Component {
case generic
case profile
case thumbnail
case preview
}
let context: AccountContext
@ -97,7 +98,7 @@ public final class GiftItemComponent: Component {
public init(
context: AccountContext,
theme: PresentationTheme,
peer: GiftItemComponent.Peer?,
peer: GiftItemComponent.Peer? = nil,
subject: GiftItemComponent.Subject,
title: String? = nil,
subtitle: String? = nil,
@ -227,6 +228,10 @@ public final class GiftItemComponent: Component {
size = CGSize(width: availableSize.width, height: availableSize.width)
iconSize = CGSize(width: floor(size.width * 0.7), height: floor(size.width * 0.7))
cornerRadius = floor(availableSize.width * 0.2)
case .preview:
size = availableSize
iconSize = CGSize(width: floor(size.width * 0.6), height: floor(size.width * 0.6))
cornerRadius = 4.0
}
self.backgroundLayer.cornerRadius = cornerRadius

View File

@ -72,3 +72,39 @@ public extension WallpaperPreviewMedia {
}
}
}
public final class UniqueGiftPreviewMedia: Media {
public var id: MediaId? {
return nil
}
public let peerIds: [PeerId] = []
public let content: StarGift.UniqueGift?
public init(content: StarGift.UniqueGift) {
self.content = content
}
public init(decoder: PostboxDecoder) {
self.content = nil
}
public func encode(_ encoder: PostboxEncoder) {
}
public func isEqual(to other: Media) -> Bool {
guard let other = other as? UniqueGiftPreviewMedia else {
return false
}
if self.content != other.content {
return false
}
return true
}
public func isSemanticallyEqual(to other: Media) -> Bool {
return self.isEqual(to: other)
}
}