diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 533b8013f6..7d12d87d6b 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -4403,14 +4403,24 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { func scrollToTop() -> Bool { if !self.mediaNode.isHidden { return self.mediaNode.scrollToTop() - } - let offset = self.listNode.visibleContentOffset() - switch offset { - case let .known(value) where value <= CGFloat.ulpOfOne: - return false - default: - self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) - return true + } else if !self.recentListNode.isHidden { + let offset = self.recentListNode.visibleContentOffset() + switch offset { + case let .known(value) where value <= CGFloat.ulpOfOne: + return false + default: + self.recentListNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + return true + } + } else { + let offset = self.listNode.visibleContentOffset() + switch offset { + case let .known(value) where value <= CGFloat.ulpOfOne: + return false + default: + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + return true + } } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift index 21b8b81a5d..798e63e8f5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift @@ -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 } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index fe382630ff..11569668ea 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -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, diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/BUILD index 0803f2a11f..660c84d84c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/BUILD @@ -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 = [ diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift index 26da378aa8..bcdf9bc7e1 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveMediaNode/Sources/ChatMessageInteractiveMediaNode.swift @@ -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? 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 + 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) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift index d87fe99d94..ab53dd68ed 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -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 } diff --git a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift index a2ac2dd942..9ef28bae36 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift @@ -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 diff --git a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift index 6f189e3089..e04ae5ff85 100644 --- a/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Components/PeerSelectionController/Sources/PeerSelectionControllerNode.swift @@ -1274,6 +1274,9 @@ final class PeerSelectionControllerNode: ASDisplayNode { if updated { strongSelf.textInputPanelNode?.updateSendButtonEnabled(count > 0, animated: true) strongSelf.requestDeactivateSearch?() + if let (layout, navigationBarHeight, actualNavigationBarHeight) = strongSelf.containerLayout { + strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, actualNavigationBarHeight: actualNavigationBarHeight, transition: .immediate) + } } else if let requestOpenPeerFromSearch = strongSelf.requestOpenPeerFromSearch { requestOpenPeerFromSearch(peer, threadId) } diff --git a/submodules/TelegramUI/Components/WallpaperPreviewMedia/Sources/WallpaperPreviewMedia.swift b/submodules/TelegramUI/Components/WallpaperPreviewMedia/Sources/WallpaperPreviewMedia.swift index 7db183dbf5..647bd5f3e5 100644 --- a/submodules/TelegramUI/Components/WallpaperPreviewMedia/Sources/WallpaperPreviewMedia.swift +++ b/submodules/TelegramUI/Components/WallpaperPreviewMedia/Sources/WallpaperPreviewMedia.swift @@ -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) + } +} diff --git a/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift b/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift index 5769326ba9..da8e19073d 100644 --- a/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift +++ b/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift @@ -324,7 +324,8 @@ private final class WebAppMessagePreviewSheetComponent: CombinedComponent { preparedMessage: context.component.preparedMessage, dismiss: { animateOut.invoke(Action { _ in - if let controller = controller() { + if let controller = controller() as? WebAppMessagePreviewScreen { + controller.completeWithResult(false) controller.dismiss(completion: nil) } })