Modernize quick reaction

This commit is contained in:
Isaac 2023-11-24 01:21:36 +04:00
parent 11b5940f07
commit b631780d00
27 changed files with 403 additions and 140 deletions

View File

@ -894,7 +894,7 @@ public protocol SharedAccountContext: AnyObject {
selectedMessages: Signal<Set<MessageId>?, NoError>, selectedMessages: Signal<Set<MessageId>?, NoError>,
mode: ChatHistoryListMode mode: ChatHistoryListMode
) -> ChatHistoryListNode ) -> ChatHistoryListNode
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, isCentered: Bool) -> ListViewItem func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, accountPeer: Peer?, isCentered: Bool) -> ListViewItem
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController? func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController

View File

@ -218,6 +218,12 @@ public final class ReactionIconView: PortalSourceView {
disposable.dispose() disposable.dispose()
} }
if !self.subviews.isEmpty {
for subview in Array(self.subviews) {
subview.removeFromSuperview()
}
}
self.context = nil self.context = nil
self.fileId = nil self.fileId = nil
self.file = nil self.file = nil

View File

@ -859,10 +859,10 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
let previewText = groupLayouts.count > 1 ? presentationData.strings.Attachment_MessagesPreview : presentationData.strings.Attachment_MessagePreview let previewText = groupLayouts.count > 1 ? presentationData.strings.Attachment_MessagesPreview : presentationData.strings.Attachment_MessagePreview
let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: previewText, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let previewMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: previewText, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true) let previewItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [previewMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true)
let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let dragMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: presentationData.strings.Attachment_DragToReorder, entities: []))], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, isCentered: true) let dragItem = self.context.sharedContext.makeChatMessagePreviewItem(context: context, messages: [dragMessage], theme: theme, strings: presentationData.strings, wallpaper: wallpaper, fontSize: presentationData.chatFontSize, chatBubbleCorners: bubbleCorners, dateTimeFormat: presentationData.dateTimeFormat, nameOrder: presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: true)
let headerItems: [ListViewItem] = [previewItem, dragItem] let headerItems: [ListViewItem] = [previewItem, dragItem]

View File

@ -116,6 +116,7 @@ swift_library(
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen", "//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen",
"//submodules/TelegramUI/Components/Settings/PeerNameColorScreen", "//submodules/TelegramUI/Components/Settings/PeerNameColorScreen",
"//submodules/ManagedAnimationNode:ManagedAnimationNode", "//submodules/ManagedAnimationNode:ManagedAnimationNode",
"//submodules/TelegramUI/Components/Settings/QuickReactionSetupController",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -170,20 +170,20 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)]
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -149,7 +149,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil, flags: []) let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil, flags: [])
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, isCentered: false) let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false)
var node: ListViewItemNode? var node: ListViewItemNode?
if let current = currentNode { if let current = currentNode {

View File

@ -18,6 +18,7 @@ import ShareController
import WebPBinding import WebPBinding
import ReactionImageComponent import ReactionImageComponent
import FeaturedStickersScreen import FeaturedStickersScreen
import QuickReactionSetupController
private final class InstalledStickerPacksControllerArguments { private final class InstalledStickerPacksControllerArguments {
let context: AccountContext let context: AccountContext

View File

@ -434,20 +434,20 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)] let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: Data(base64Encoded: waveformBase64)!)]
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.chatBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -1077,7 +1077,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
return state return state
}, animated: true) }, animated: true)
}, clickThroughMessage: { }, clickThroughMessage: {
}, backgroundNode: self.backgroundNode, availableReactions: nil, isCentered: false) }, backgroundNode: self.backgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false)
return item return item
} }

View File

@ -617,7 +617,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
sampleMessages.append(message8) sampleMessages.append(message8)
items = sampleMessages.reversed().map { message in items = sampleMessages.reversed().map { message in
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperNode, availableReactions: nil, isCentered: false) self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.wallpaperNode, availableReactions: nil, accountPeer: nil, isCentered: false)
} }
let width: CGFloat let width: CGFloat

View File

@ -168,7 +168,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
} }
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, isCentered: false)) items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
} }
var nodes: [ListViewItemNode] = [] var nodes: [ListViewItemNode] = []

View File

@ -1580,17 +1580,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let theme = self.presentationData.theme let theme = self.presentationData.theme
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false))
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false))
if let serviceMessageText { if let serviceMessageText {
let attributedText = convertMarkdownToAttributes(NSAttributedString(string: serviceMessageText)) let attributedText = convertMarkdownToAttributes(NSAttributedString(string: serviceMessageText))
let entities = generateChatInputTextEntities(attributedText) let entities = generateChatInputTextEntities(attributedText)
let message3 = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: attributedText.string, entities: entities))], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message3 = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [TelegramMediaAction(action: .customText(text: attributedText.string, entities: entities))], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, isCentered: false)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: self.nativeNode, availableReactions: nil, accountPeer: nil, isCentered: false))
} }
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height) let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)

View File

@ -1373,5 +1373,5 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
} }
public func shouldDisplayInlineDateReactions(message: Message, isPremium: Bool, forceInline: Bool) -> Bool { public func shouldDisplayInlineDateReactions(message: Message, isPremium: Bool, forceInline: Bool) -> Bool {
return forceInline return false
} }

View File

@ -31,6 +31,7 @@ swift_library(
"//submodules/PremiumUI", "//submodules/PremiumUI",
"//submodules/UndoUI", "//submodules/UndoUI",
"//submodules/TextFormat", "//submodules/TextFormat",
"//submodules/Components/HierarchyTrackingLayer",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -7,6 +7,47 @@ import ComponentDisplayAdapters
import SwitchComponent import SwitchComponent
import EntityKeyboard import EntityKeyboard
import AccountContext import AccountContext
import HierarchyTrackingLayer
private final class CaretIndicatorView: UIImageView {
private let hierarchyTrackingLayer: HierarchyTrackingLayer
override init(frame: CGRect) {
self.hierarchyTrackingLayer = HierarchyTrackingLayer()
super.init(frame: frame)
self.layer.addSublayer(self.hierarchyTrackingLayer)
self.hierarchyTrackingLayer.didEnterHierarchy = { [weak self] in
self?.restartAnimations(delayStart: false)
}
}
required init?(coder: NSCoder) {
preconditionFailure()
}
func restartAnimations(delayStart: Bool) {
self.layer.removeAnimation(forKey: "caret")
let animation = CAKeyframeAnimation(keyPath: "opacity")
animation.values = [1.0 as NSNumber, 0.0 as NSNumber, 1.0 as NSNumber, 1.0 as NSNumber]
let firstDuration = 0.3
let secondDuration = 0.25
let restDuration = 0.35
let duration = firstDuration + secondDuration + restDuration
let keyTimes: [NSNumber] = [0.0 as NSNumber, (firstDuration / duration) as NSNumber, ((firstDuration + secondDuration) / duration) as NSNumber, ((firstDuration + secondDuration + restDuration) / duration) as NSNumber]
animation.keyTimes = keyTimes
animation.duration = duration
animation.repeatCount = Float.greatestFiniteMagnitude
animation.fillMode = .both
if delayStart {
animation.beginTime = self.layer.convertTime(CACurrentMediaTime(), from: nil) + 0.8 * UIView.animationDurationFactor()
}
self.layer.add(animation, forKey: "caret")
}
}
final class EmojiListInputComponent: Component { final class EmojiListInputComponent: Component {
let context: AccountContext let context: AccountContext
@ -66,10 +107,10 @@ final class EmojiListInputComponent: Component {
private var itemLayers: [Int64: EmojiPagerContentComponent.View.ItemLayer] = [:] private var itemLayers: [Int64: EmojiPagerContentComponent.View.ItemLayer] = [:]
private let trailingPlaceholder = ComponentView<Empty>() private let trailingPlaceholder = ComponentView<Empty>()
private let caretIndicator: UIImageView private let caretIndicator: CaretIndicatorView
override init(frame: CGRect) { override init(frame: CGRect) {
self.caretIndicator = UIImageView() self.caretIndicator = CaretIndicatorView(frame: CGRect())
self.caretIndicator.image = generateImage(CGSize(width: 2.0, height: 4.0), rotatedContext: { size, context in self.caretIndicator.image = generateImage(CGSize(width: 2.0, height: 4.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor) context.setFillColor(UIColor.white.cgColor)
@ -115,6 +156,14 @@ final class EmojiListInputComponent: Component {
} }
} }
func caretRect() -> CGRect? {
if !self.caretIndicator.isHidden {
return self.caretIndicator.frame
} else {
return nil
}
}
func update(component: EmojiListInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize { func update(component: EmojiListInputComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
let verticalInset: CGFloat = 12.0 let verticalInset: CGFloat = 12.0
let placeholderSpacing: CGFloat = 6.0 let placeholderSpacing: CGFloat = 6.0
@ -136,6 +185,10 @@ final class EmojiListInputComponent: Component {
var rowCount = (component.reactionItems.count + (itemsPerRow - 1)) / itemsPerRow var rowCount = (component.reactionItems.count + (itemsPerRow - 1)) / itemsPerRow
rowCount = max(1, rowCount) rowCount = max(1, rowCount)
if let previousComponent = self.component, (previousComponent.reactionItems.count != component.reactionItems.count || previousComponent.isInputActive != component.isInputActive) {
self.caretIndicator.restartAnimations(delayStart: true)
}
self.component = component self.component = component
self.state = state self.state = state
@ -174,9 +227,7 @@ final class EmojiListInputComponent: Component {
self.caretIndicator.tintColor = component.theme.list.itemAccentColor self.caretIndicator.tintColor = component.theme.list.itemAccentColor
self.caretIndicator.isHidden = !component.isInputActive self.caretIndicator.isHidden = !component.isInputActive
if component.caretPosition >= component.reactionItems.count { var caretFrame = CGRect(origin: CGPoint(x: trailingPlaceholderFrame.minX, y: trailingPlaceholderFrame.minY + floorToScreenPixels((trailingPlaceholderFrame.height - 22.0) * 0.5)), size: CGSize(width: 2.0, height: 22.0))
transition.setFrame(view: self.caretIndicator, frame: CGRect(origin: CGPoint(x: trailingPlaceholderFrame.minX, y: trailingPlaceholderFrame.minY + floorToScreenPixels((trailingPlaceholderFrame.height - 22.0) * 0.5)), size: CGSize(width: 2.0, height: 22.0)))
}
var validIds: [Int64] = [] var validIds: [Int64] = []
for i in 0 ..< component.reactionItems.count { for i in 0 ..< component.reactionItems.count {
@ -205,7 +256,7 @@ final class EmojiListInputComponent: Component {
itemFile: item.file, itemFile: item.file,
subgroupId: nil, subgroupId: nil,
icon: .none, icon: .none,
tintMode: .none tintMode: item.file.isCustomTemplateEmoji ? .primary : .none
), ),
context: component.context, context: component.context,
attemptSynchronousLoad: false, attemptSynchronousLoad: false,
@ -214,7 +265,7 @@ final class EmojiListInputComponent: Component {
renderer: component.context.animationRenderer, renderer: component.context.animationRenderer,
placeholderColor: component.theme.list.mediaPlaceholderColor, placeholderColor: component.theme.list.mediaPlaceholderColor,
blurredBadgeColor: .clear, blurredBadgeColor: .clear,
accentIconColor: component.theme.list.itemAccentColor, accentIconColor: component.theme.list.itemPrimaryTextColor,
pointSize: CGSize(width: 32.0, height: 32.0), pointSize: CGSize(width: 32.0, height: 32.0),
onUpdateDisplayPlaceholder: { _, _ in onUpdateDisplayPlaceholder: { _, _ in
} }
@ -224,10 +275,19 @@ final class EmojiListInputComponent: Component {
} }
itemLayer.isVisibleForAnimations = true itemLayer.isVisibleForAnimations = true
switch itemLayer.item.tintMode {
case .none:
itemLayer.layerTintColor = nil
case .accent, .primary, .custom:
itemLayer.layerTintColor = component.theme.list.itemPrimaryTextColor.cgColor
}
itemTransition.setFrame(layer: itemLayer, frame: itemFrame) itemTransition.setFrame(layer: itemLayer, frame: itemFrame)
if component.caretPosition == i { if component.caretPosition == i {
transition.setFrame(view: self.caretIndicator, frame: CGRect(origin: CGPoint(x: itemFrame.minX - 2.0, y: itemFrame.minY + floorToScreenPixels((itemFrame.height - 22.0) * 0.5)), size: CGSize(width: 2.0, height: 22.0))) caretFrame = CGRect(origin: CGPoint(x: itemFrame.minX - 2.0, y: itemFrame.minY + floorToScreenPixels((itemFrame.height - 22.0) * 0.5)), size: CGSize(width: 2.0, height: 22.0))
} else if i == component.reactionItems.count - 1 && component.caretPosition == i + 1 {
caretFrame = CGRect(origin: CGPoint(x: itemFrame.maxX + itemSpacing, y: itemFrame.minY + floorToScreenPixels((itemFrame.height - 22.0) * 0.5)), size: CGSize(width: 2.0, height: 22.0))
} }
if animateIn, !transition.animation.isImmediate { if animateIn, !transition.animation.isImmediate {
@ -255,6 +315,22 @@ final class EmojiListInputComponent: Component {
self.itemLayers.removeValue(forKey: key) self.itemLayers.removeValue(forKey: key)
} }
if !transition.animation.isImmediate && abs(caretFrame.midY - self.caretIndicator.center.y) > 2.0 {
if let caretSnapshot = self.caretIndicator.snapshotView(afterScreenUpdates: false) {
caretSnapshot.frame = self.caretIndicator.frame
self.insertSubview(caretSnapshot, aboveSubview: self.caretIndicator)
caretSnapshot.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak caretSnapshot] _ in
caretSnapshot?.removeFromSuperview()
})
caretSnapshot.layer.animateScale(from: 1.0, to: 0.001, duration: 0.15, removeOnCompletion: false)
}
self.caretIndicator.frame = caretFrame
self.caretIndicator.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
self.caretIndicator.layer.animateScale(from: 0.001, to: 1.0, duration: 0.15)
} else {
transition.setFrame(view: self.caretIndicator, frame: caretFrame)
}
return CGSize(width: availableSize.width, height: contentHeight) return CGSize(width: availableSize.width, height: contentHeight)
} }
} }

View File

@ -7,6 +7,7 @@ import ComponentDisplayAdapters
import EntityKeyboard import EntityKeyboard
import AccountContext import AccountContext
import PagerComponent import PagerComponent
import AudioToolbox
public final class EmojiSelectionComponent: Component { public final class EmojiSelectionComponent: Component {
public typealias EnvironmentType = Empty public typealias EnvironmentType = Empty
@ -89,8 +90,8 @@ public final class EmojiSelectionComponent: Component {
private let shadowView: UIImageView private let shadowView: UIImageView
private let cornersView: UIImageView private let cornersView: UIImageView
private let backspaceButton = ComponentView<Empty>()
private let backspaceBackgroundView: UIImageView private let backspaceBackgroundView: UIImageView
private let backspaceButtonView: HighlightTrackingButton
private var component: EmojiSelectionComponent? private var component: EmojiSelectionComponent?
private weak var state: EmptyComponentState? private weak var state: EmptyComponentState?
@ -105,7 +106,6 @@ public final class EmojiSelectionComponent: Component {
self.cornersView = UIImageView() self.cornersView = UIImageView()
self.backspaceBackgroundView = UIImageView() self.backspaceBackgroundView = UIImageView()
self.backspaceButtonView = HighlightTrackingButton()
super.init(frame: frame) super.init(frame: frame)
@ -116,9 +116,6 @@ public final class EmojiSelectionComponent: Component {
self.addSubview(self.cornersView) self.addSubview(self.cornersView)
self.addSubview(self.shadowView) self.addSubview(self.shadowView)
self.backspaceButtonView.addSubview(self.backspaceBackgroundView)
self.addSubview(self.backspaceButtonView)
self.shadowView.image = generateImage(CGSize(width: 16.0, height: 16.0), rotatedContext: { size, context in self.shadowView.image = generateImage(CGSize(width: 16.0, height: 16.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
context.setShadow(offset: CGSize(), blur: 40.0, color: UIColor(white: 0.0, alpha: 0.05).cgColor) context.setShadow(offset: CGSize(), blur: 40.0, color: UIColor(white: 0.0, alpha: 0.05).cgColor)
@ -138,35 +135,6 @@ public final class EmojiSelectionComponent: Component {
context.fillPath() context.fillPath()
context.clear(CGRect(origin: CGPoint(x: 8.0, y: 0.0), size: CGSize(width: 1.0, height: size.height))) context.clear(CGRect(origin: CGPoint(x: 8.0, y: 0.0), size: CGSize(width: 1.0, height: size.height)))
})?.withRenderingMode(.alwaysTemplate).stretchableImage(withLeftCapWidth: 8, topCapHeight: 16) })?.withRenderingMode(.alwaysTemplate).stretchableImage(withLeftCapWidth: 8, topCapHeight: 16)
self.backspaceButtonView.highligthedChanged = { [weak self] highlighted in
if let self, self.backspaceButtonView.bounds.width > 0.0 {
let topScale: CGFloat = (self.backspaceButtonView.bounds.width - 8.0) / self.backspaceButtonView.bounds.width
let maxScale: CGFloat = (self.backspaceButtonView.bounds.width + 2.0) / self.backspaceButtonView.bounds.width
if highlighted {
self.backspaceButtonView.layer.removeAnimation(forKey: "sublayerTransform")
self.backspaceButtonView.alpha = 0.7
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
transition.setScale(layer: self.backspaceButtonView.layer, scale: topScale)
} else {
self.backspaceButtonView.alpha = 1.0
self.backspaceButtonView.layer.animateAlpha(from: 7, to: 1.0, duration: 0.2)
let transition = Transition(animation: .none)
transition.setScale(layer: self.backspaceButtonView.layer, scale: 1.0)
self.backspaceButtonView.layer.animateScale(from: topScale, to: maxScale, duration: 0.13, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
guard let self else {
return
}
self.backspaceButtonView.layer.animateScale(from: maxScale, to: 1.0, duration: 0.1, timingFunction: CAMediaTimingFunctionName.easeIn.rawValue)
})
}
}
}
self.backspaceButtonView.addTarget(self, action: #selector(self.backspacePressed), for: .touchUpInside)
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
@ -176,10 +144,6 @@ public final class EmojiSelectionComponent: Component {
deinit { deinit {
} }
@objc private func backspacePressed() {
self.component?.backspace?()
}
func update(component: EmojiSelectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize { func update(component: EmojiSelectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
self.backgroundColor = component.backgroundColor self.backgroundColor = component.backgroundColor
let panelBackgroundColor = component.backgroundColor.withMultipliedAlpha(0.85) let panelBackgroundColor = component.backgroundColor.withMultipliedAlpha(0.85)
@ -199,6 +163,29 @@ public final class EmojiSelectionComponent: Component {
let backspaceButtonInset = UIEdgeInsets(top: 9.0, left: 0.0, bottom: 36.0, right: 9.0) let backspaceButtonInset = UIEdgeInsets(top: 9.0, left: 0.0, bottom: 36.0, right: 9.0)
let backspaceButtonSize = CGSize(width: 36.0, height: 36.0) let backspaceButtonSize = CGSize(width: 36.0, height: 36.0)
let _ = self.backspaceButton.update(
transition: transition,
component: AnyComponent(Button(
content: AnyComponent(HStack([], spacing: 0.0)),
action: { [weak self] in
guard let self, let component = self.component else {
return
}
component.backspace?()
AudioServicesPlaySystemSound(1155)
}
).withHoldAction({ [weak self] in
guard let self, let component = self.component else {
return
}
AudioServicesPlaySystemSound(1155)
component.backspace?()
})),
environment: {},
containerSize: backspaceButtonSize
)
if previousComponent?.theme !== component.theme { if previousComponent?.theme !== component.theme {
self.backspaceBackgroundView.image = generateImage(CGSize(width: backspaceButtonSize.width + 12.0 * 2.0, height: backspaceButtonSize.height + 12.0 * 2.0), rotatedContext: { size, context in self.backspaceBackgroundView.image = generateImage(CGSize(width: backspaceButtonSize.width + 12.0 * 2.0, height: backspaceButtonSize.height + 12.0 * 2.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size)) context.clear(CGRect(origin: CGPoint(), size: size))
@ -215,14 +202,22 @@ public final class EmojiSelectionComponent: Component {
} }
self.backspaceBackgroundView.frame = CGRect(origin: CGPoint(), size: backspaceButtonSize).insetBy(dx: -12.0, dy: -12.0) self.backspaceBackgroundView.frame = CGRect(origin: CGPoint(), size: backspaceButtonSize).insetBy(dx: -12.0, dy: -12.0)
let backspaceButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - component.sideInset - backspaceButtonInset.right - backspaceButtonSize.width, y: availableSize.height - component.bottomInset - backspaceButtonInset.bottom), size: backspaceButtonSize) let backspaceButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - component.sideInset - backspaceButtonInset.right - backspaceButtonSize.width, y: availableSize.height - component.bottomInset - backspaceButtonInset.bottom), size: backspaceButtonSize)
transition.setPosition(view: self.backspaceButtonView, position: backspaceButtonFrame.center)
transition.setBounds(view: self.backspaceButtonView, bounds: CGRect(origin: CGPoint(), size: backspaceButtonFrame.size)) if let backspaceButtonView = self.backspaceButton.view {
if backspaceButtonView.superview == nil {
backspaceButtonView.addSubview(self.backspaceBackgroundView)
self.addSubview(backspaceButtonView)
}
transition.setPosition(view: backspaceButtonView, position: backspaceButtonFrame.center)
transition.setBounds(view: backspaceButtonView, bounds: CGRect(origin: CGPoint(), size: backspaceButtonFrame.size))
if component.backspace != nil { if component.backspace != nil {
transition.setAlpha(view: self.backspaceButtonView, alpha: 1.0) transition.setAlpha(view: backspaceButtonView, alpha: 1.0)
transition.setScale(view: self.backspaceButtonView, scale: 1.0) transition.setScale(view: backspaceButtonView, scale: 1.0)
} else { } else {
transition.setAlpha(view: self.backspaceButtonView, alpha: 0.0) transition.setAlpha(view: backspaceButtonView, alpha: 0.0)
transition.setScale(view: self.backspaceButtonView, scale: 0.001) transition.setScale(view: backspaceButtonView, scale: 0.001)
}
} }
let keyboardSize = self.keyboardView.update( let keyboardSize = self.keyboardView.update(
@ -233,7 +228,7 @@ public final class EmojiSelectionComponent: Component {
isContentInFocus: false, isContentInFocus: false,
containerInsets: UIEdgeInsets(top: topPanelHeight - 34.0, left: component.sideInset, bottom: component.bottomInset + 16.0, right: component.sideInset), containerInsets: UIEdgeInsets(top: topPanelHeight - 34.0, left: component.sideInset, bottom: component.bottomInset + 16.0, right: component.sideInset),
topPanelInsets: UIEdgeInsets(top: 0.0, left: 4.0, bottom: 0.0, right: 4.0), topPanelInsets: UIEdgeInsets(top: 0.0, left: 4.0, bottom: 0.0, right: 4.0),
emojiContent: component.emojiContent, emojiContent: component.emojiContent.withCustomTintColor(component.theme.list.itemPrimaryTextColor),
stickerContent: nil, stickerContent: nil,
maskContent: nil, maskContent: nil,
gifContent: nil, gifContent: nil,

View File

@ -19,6 +19,7 @@ import UndoUI
import BundleIconComponent import BundleIconComponent
import AnimatedTextComponent import AnimatedTextComponent
import TextFormat import TextFormat
import AudioToolbox
private final class ButtonSubtitleComponent: CombinedComponent { private final class ButtonSubtitleComponent: CombinedComponent {
let count: Int let count: Int
@ -136,6 +137,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
private var caretPosition: Int? private var caretPosition: Int?
private var displayInput: Bool = false private var displayInput: Bool = false
private var recenterOnCaret: Bool = false
private var isApplyingSettings: Bool = false private var isApplyingSettings: Bool = false
private var applyDisposable: Disposable? private var applyDisposable: Disposable?
@ -209,14 +211,14 @@ final class PeerAllowedReactionsScreenComponent: Component {
} else { } else {
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
//TODO:localize //TODO:localize
self.environment?.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "Save Changes?", actions: [ self.environment?.controller()?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: "Unsaved Changes", text: "You have changed the list of reactions. Apply changes?", actions: [
TextAlertAction(type: .genericAction, title: "Discard", action: { [weak self] in TextAlertAction(type: .genericAction, title: "Discard", action: { [weak self] in
guard let self else { guard let self else {
return return
} }
self.environment?.controller()?.dismiss() self.environment?.controller()?.dismiss()
}), }),
TextAlertAction(type: .defaultAction, title: "Save", action: { [weak self] in TextAlertAction(type: .defaultAction, title: "Apply", action: { [weak self] in
guard let self else { guard let self else {
return return
} }
@ -446,12 +448,30 @@ final class PeerAllowedReactionsScreenComponent: Component {
return return
} }
AudioServicesPlaySystemSound(0x450)
if let index = enabledReactions.firstIndex(where: { $0.file.fileId.id == itemFile.fileId.id }) { if let index = enabledReactions.firstIndex(where: { $0.file.fileId.id == itemFile.fileId.id }) {
enabledReactions.remove(at: index) enabledReactions.remove(at: index)
if let caretPosition = self.caretPosition, caretPosition > index { if let caretPosition = self.caretPosition, caretPosition > index {
self.caretPosition = max(0, caretPosition - 1) self.caretPosition = max(0, caretPosition - 1)
} }
} else { } else {
if enabledReactions.count >= 100 {
//TODO:localize
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
var animateAsReplacement = false
if let currentUndoController = self.currentUndoController {
currentUndoController.dismiss()
animateAsReplacement = true
}
let undoController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "You can select at most 100 reactions.", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: animateAsReplacement, action: { _ in return false })
self.currentUndoController = undoController
self.environment?.controller()?.present(undoController, in: .current)
return
}
let reaction: MessageReaction.Reaction let reaction: MessageReaction.Reaction
if let availableReactions = self.availableReactions, let reactionItem = availableReactions.reactions.first(where: { $0.selectAnimation.fileId.id == itemFile.fileId.id }) { if let availableReactions = self.availableReactions, let reactionItem = availableReactions.reactions.first(where: { $0.selectAnimation.fileId.id == itemFile.fileId.id }) {
reaction = reactionItem.value reaction = reactionItem.value
@ -479,7 +499,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
animateAsReplacement = true animateAsReplacement = true
} }
let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: itemFile, loop: false, title: nil, text: "Your channel needs to reach **Level \(nextCustomReactionCount)** to add **\(nextCustomReactionCount) custom emoji as reactions.**", undoText: nil, customAction: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: animateAsReplacement, action: { _ in return false }) let undoController = UndoOverlayController(presentationData: presentationData, content: .customEmoji(context: component.context, file: itemFile, loop: false, title: nil, text: "Your channel needs to reach **Level \(nextCustomReactionCount)** to add **\(nextCustomReactionCount)** custom emoji as reactions.**", undoText: nil, customAction: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: animateAsReplacement, action: { _ in return false })
self.currentUndoController = undoController self.currentUndoController = undoController
self.environment?.controller()?.present(undoController, in: .current) self.environment?.controller()?.present(undoController, in: .current)
} }
@ -494,6 +514,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
enabledReactions.append(item) enabledReactions.append(item)
self.caretPosition = enabledReactions.count self.caretPosition = enabledReactions.count
} }
self.recenterOnCaret = true
} }
self.enabledReactions = enabledReactions self.enabledReactions = enabledReactions
if !self.isUpdating { if !self.isUpdating {
@ -707,6 +728,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
} }
if self.emojiContent != nil && !self.displayInput { if self.emojiContent != nil && !self.displayInput {
self.displayInput = true self.displayInput = true
self.recenterOnCaret = true
self.state?.updated(transition: .spring(duration: 0.5)) self.state?.updated(transition: .spring(duration: 0.5))
} }
}, },
@ -936,10 +958,12 @@ final class PeerAllowedReactionsScreenComponent: Component {
if caretPosition > 0 { if caretPosition > 0 {
enabledReactions.remove(at: caretPosition - 1) enabledReactions.remove(at: caretPosition - 1)
self.caretPosition = caretPosition - 1 self.caretPosition = caretPosition - 1
self.recenterOnCaret = true
} }
} else { } else {
enabledReactions.removeLast() enabledReactions.removeLast()
self.caretPosition = enabledReactions.count self.caretPosition = enabledReactions.count
self.recenterOnCaret = true
} }
self.enabledReactions = enabledReactions self.enabledReactions = enabledReactions
if !self.isUpdating { if !self.isUpdating {
@ -1007,6 +1031,25 @@ final class PeerAllowedReactionsScreenComponent: Component {
self.scrollView.scrollIndicatorInsets = scrollInsets self.scrollView.scrollIndicatorInsets = scrollInsets
} }
if self.recenterOnCaret {
self.recenterOnCaret = false
if let reactionInputView = self.reactionInput?.view as? EmojiListInputComponent.View, let localCaretRect = reactionInputView.caretRect() {
let caretRect = reactionInputView.convert(localCaretRect, to: self.scrollView)
var scrollViewBounds = self.scrollView.bounds
let minButtonDistance: CGFloat = 16.0
if -scrollViewBounds.minY + caretRect.maxY > buttonFrame.minY - minButtonDistance {
scrollViewBounds.origin.y = -(buttonFrame.minY - minButtonDistance - caretRect.maxY)
if scrollViewBounds.origin.y < 0.0 {
scrollViewBounds.origin.y = 0.0
}
}
if self.scrollView.bounds != scrollViewBounds {
transition.setBounds(view: self.scrollView, bounds: scrollViewBounds)
}
}
}
self.updateScrolling(transition: transition) self.updateScrolling(transition: transition)
return availableSize return availableSize
@ -1077,6 +1120,9 @@ public class PeerAllowedReactionsScreen: ViewControllerComponentContainer {
initialContent: initialContent initialContent: initialContent
), navigationBarAppearance: .default, theme: .default) ), navigationBarAppearance: .default, theme: .default)
//TODO:localize
self.title = "Reactions"
self.scrollToTop = { [weak self] in self.scrollToTop = { [weak self] in
guard let self, let componentView = self.node.hostView.componentView as? PeerAllowedReactionsScreenComponent.View else { guard let self, let componentView = self.node.hostView.componentView as? PeerAllowedReactionsScreenComponent.View else {
return return

View File

@ -197,7 +197,7 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
} }
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[authorPeerId], text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)] : [], media: media, peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[authorPeerId], text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId, threadMessageId: nil, quote: nil, isQuote: false)] : [], media: media, peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, isCentered: false)) items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false))
} }
var nodes: [ListViewItemNode] = [] var nodes: [ListViewItemNode] = []

View File

@ -18,15 +18,18 @@ private final class PeerNameColorScreenArguments {
let context: AccountContext let context: AccountContext
let updateNameColor: (PeerNameColor?) -> Void let updateNameColor: (PeerNameColor?) -> Void
let updateBackgroundEmojiId: (Int64?) -> Void let updateBackgroundEmojiId: (Int64?) -> Void
let resetColor: () -> Void
init( init(
context: AccountContext, context: AccountContext,
updateNameColor: @escaping (PeerNameColor?) -> Void, updateNameColor: @escaping (PeerNameColor?) -> Void,
updateBackgroundEmojiId: @escaping (Int64?) -> Void updateBackgroundEmojiId: @escaping (Int64?) -> Void,
resetColor: @escaping () -> Void
) { ) {
self.context = context self.context = context
self.updateNameColor = updateNameColor self.updateNameColor = updateNameColor
self.updateBackgroundEmojiId = updateBackgroundEmojiId self.updateBackgroundEmojiId = updateBackgroundEmojiId
self.resetColor = resetColor
} }
} }
@ -213,7 +216,7 @@ private enum PeerNameColorScreenEntry: ItemListNodeEntry {
case .removeColor: case .removeColor:
//TODO:localize //TODO:localize
return ItemListActionItem(presentationData: presentationData, title: "Reset Profile Color", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { return ItemListActionItem(presentationData: presentationData, title: "Reset Profile Color", kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.updateNameColor(nil) arguments.resetColor()
}) })
case let .colorDescription(text): case let .colorDescription(text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
@ -447,6 +450,19 @@ public func PeerNameColorScreen(
} }
return updatedState return updatedState
} }
},
resetColor: {
updateState { state in
var updatedState = state
if state.selectedTabIndex == 1 {
updatedState.updatedProfileColor = nil
updatedState.hasUpdatedProfileColor = true
updatedState.updatedProfileBackgroundEmojiId = nil
updatedState.hasUpdatedProfileBackgroundEmojiId = true
}
return updatedState
}
} }
) )

View File

@ -0,0 +1,36 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "QuickReactionSetupController",
module_name = "QuickReactionSetupController",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AccountContext",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/AsyncDisplayKit",
"//submodules/ComponentFlow",
"//submodules/Display",
"//submodules/TelegramUI/Components/EmojiStatusComponent",
"//submodules/TelegramUI/Components/EmojiStatusSelectionComponent",
"//submodules/TelegramUI/Components/EntityKeyboard",
"//submodules/ItemListUI",
"//submodules/Postbox",
"//submodules/PresentationDataUtils",
"//submodules/Components/ReactionImageComponent",
"//submodules/ReactionSelectionNode",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
"//submodules/WallpaperBackgroundNode",
"//submodules/WebPBinding",
],
visibility = [
"//visibility:public",
],
)

View File

@ -46,7 +46,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
} }
case demoHeader(String) case demoHeader(String)
case demoMessage(wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: MessageReaction.Reaction?) case demoMessage(wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, bubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: MessageReaction.Reaction?, accountPeer: Peer?)
case demoDescription(String) case demoDescription(String)
case quickReaction(String, MessageReaction.Reaction, AvailableReactions) case quickReaction(String, MessageReaction.Reaction, AvailableReactions)
case quickReactionDescription(String) case quickReactionDescription(String)
@ -98,8 +98,8 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .demoMessage(lhsWallpaper, lhsFontSize, lhsBubbleCorners, lhsDateTimeFormat, lhsNameDisplayOrder, lhsAvailableReactions, lhsReaction): case let .demoMessage(lhsWallpaper, lhsFontSize, lhsBubbleCorners, lhsDateTimeFormat, lhsNameDisplayOrder, lhsAvailableReactions, lhsReaction, lhsAccountPeer):
if case let .demoMessage(rhsWallpaper, rhsFontSize, rhsBubbleCorners, rhsDateTimeFormat, rhsNameDisplayOrder, rhsAvailableReactions, rhsReaction) = rhs, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsBubbleCorners == rhsBubbleCorners, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, lhsAvailableReactions == rhsAvailableReactions, lhsReaction == rhsReaction { if case let .demoMessage(rhsWallpaper, rhsFontSize, rhsBubbleCorners, rhsDateTimeFormat, rhsNameDisplayOrder, rhsAvailableReactions, rhsReaction, rhsAccountPeer) = rhs, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsBubbleCorners == rhsBubbleCorners, lhsDateTimeFormat == rhsDateTimeFormat, lhsNameDisplayOrder == rhsNameDisplayOrder, lhsAvailableReactions == rhsAvailableReactions, lhsReaction == rhsReaction, lhsAccountPeer?.id == rhsAccountPeer?.id {
return true return true
} else { } else {
return false return false
@ -134,7 +134,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
switch self { switch self {
case let .demoHeader(text): case let .demoHeader(text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .demoMessage(wallpaper, fontSize, chatBubbleCorners, dateTimeFormat, nameDisplayOrder, availableReactions, reaction): case let .demoMessage(wallpaper, fontSize, chatBubbleCorners, dateTimeFormat, nameDisplayOrder, availableReactions, reaction, accountPeer):
return ReactionChatPreviewItem( return ReactionChatPreviewItem(
context: arguments.context, context: arguments.context,
theme: presentationData.theme, theme: presentationData.theme,
@ -147,6 +147,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
nameDisplayOrder: nameDisplayOrder, nameDisplayOrder: nameDisplayOrder,
availableReactions: availableReactions, availableReactions: availableReactions,
reaction: reaction, reaction: reaction,
accountPeer: accountPeer,
toggleReaction: { toggleReaction: {
arguments.toggleReaction() arguments.toggleReaction()
} }
@ -172,7 +173,8 @@ private func quickReactionSetupControllerEntries(
availableReactions: AvailableReactions?, availableReactions: AvailableReactions?,
reactionSettings: ReactionSettings, reactionSettings: ReactionSettings,
state: QuickReactionSetupControllerState, state: QuickReactionSetupControllerState,
isPremium: Bool isPremium: Bool,
accountPeer: Peer?
) -> [QuickReactionSetupControllerEntry] { ) -> [QuickReactionSetupControllerEntry] {
var entries: [QuickReactionSetupControllerEntry] = [] var entries: [QuickReactionSetupControllerEntry] = []
@ -185,7 +187,8 @@ private func quickReactionSetupControllerEntries(
dateTimeFormat: presentationData.dateTimeFormat, dateTimeFormat: presentationData.dateTimeFormat,
nameDisplayOrder: presentationData.nameDisplayOrder, nameDisplayOrder: presentationData.nameDisplayOrder,
availableReactions: availableReactions, availableReactions: availableReactions,
reaction: state.hasReaction ? reactionSettings.effectiveQuickReaction(hasPremium: isPremium) : nil reaction: state.hasReaction ? reactionSettings.effectiveQuickReaction(hasPremium: isPremium) : nil,
accountPeer: accountPeer
)) ))
entries.append(.demoDescription(presentationData.strings.Settings_QuickReactionSetup_DemoInfo)) entries.append(.demoDescription(presentationData.strings.Settings_QuickReactionSetup_DemoInfo))
@ -257,7 +260,8 @@ public func quickReactionSetupController(
availableReactions: availableReactions, availableReactions: availableReactions,
reactionSettings: settings, reactionSettings: settings,
state: state, state: state,
isPremium: isPremium isPremium: isPremium,
accountPeer: accountPeer?._asPeer()
) )
let controllerState = ItemListControllerState( let controllerState = ItemListControllerState(
@ -283,16 +287,7 @@ public func quickReactionSetupController(
let controller = ItemListController(context: context, state: signal) let controller = ItemListController(context: context, state: signal)
controller.didScrollWithOffset = { [weak controller] offset, transition, _, _ in controller.alwaysSynchronous = true
guard let controller = controller else {
return
}
controller.forEachItemNode { itemNode in
if let itemNode = itemNode as? ReactionChatPreviewItemNode {
itemNode.standaloneReactionAnimation?.addRelativeContentOffset(CGPoint(x: 0.0, y: offset), transition: transition)
}
}
}
openQuickReactionImpl = { [weak controller] in openQuickReactionImpl = { [weak controller] in
let _ = (combineLatest(queue: .mainQueue(), let _ = (combineLatest(queue: .mainQueue(),

View File

@ -26,9 +26,10 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
let nameDisplayOrder: PresentationPersonNameOrder let nameDisplayOrder: PresentationPersonNameOrder
let availableReactions: AvailableReactions? let availableReactions: AvailableReactions?
let reaction: MessageReaction.Reaction? let reaction: MessageReaction.Reaction?
let accountPeer: Peer?
let toggleReaction: () -> Void let toggleReaction: () -> Void
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: MessageReaction.Reaction?, toggleReaction: @escaping () -> Void) { init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, wallpaper: TelegramWallpaper, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, availableReactions: AvailableReactions?, reaction: MessageReaction.Reaction?, accountPeer: Peer?, toggleReaction: @escaping () -> Void) {
self.context = context self.context = context
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
@ -40,6 +41,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
self.nameDisplayOrder = nameDisplayOrder self.nameDisplayOrder = nameDisplayOrder
self.availableReactions = availableReactions self.availableReactions = availableReactions
self.reaction = reaction self.reaction = reaction
self.accountPeer = accountPeer
self.toggleReaction = toggleReaction self.toggleReaction = toggleReaction
} }
@ -53,7 +55,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
Queue.mainQueue().async { Queue.mainQueue().async {
completion(node, { completion(node, {
return (nil, { _ in apply() }) return (nil, { _ in apply(.None) })
}) })
} }
} }
@ -68,7 +70,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
Queue.mainQueue().async { Queue.mainQueue().async {
completion(layout, { _ in completion(layout, { _ in
apply() apply(animation)
}) })
} }
} }
@ -83,6 +85,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
private let bottomStripeNode: ASDisplayNode private let bottomStripeNode: ASDisplayNode
private let maskNode: ASImageNode private let maskNode: ASImageNode
private let clippingNode: ASDisplayNode
private let containerNode: ASDisplayNode private let containerNode: ASDisplayNode
private var messageNode: ListViewItemNode? private var messageNode: ListViewItemNode?
@ -104,14 +107,17 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
self.maskNode = ASImageNode() self.maskNode = ASImageNode()
self.clippingNode = ASDisplayNode()
self.clippingNode.clipsToBounds = true
self.clippingNode.layer.cornerRadius = 10.0
self.containerNode = ASDisplayNode() self.containerNode = ASDisplayNode()
self.containerNode.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0) self.containerNode.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
super.init(layerBacked: false, dynamicBounce: false) super.init(layerBacked: false, dynamicBounce: false)
self.clipsToBounds = true self.addSubnode(self.clippingNode)
self.clippingNode.addSubnode(self.containerNode)
self.addSubnode(self.containerNode)
} }
deinit { deinit {
@ -227,15 +233,14 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
self.standaloneReactionAnimation = nil self.standaloneReactionAnimation = nil
} }
if let supernode = self.supernode {
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect) let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect)
self.loadNextGenericReactionEffect(context: item.context) self.loadNextGenericReactionEffect(context: item.context)
self.standaloneReactionAnimation = standaloneReactionAnimation self.standaloneReactionAnimation = standaloneReactionAnimation
let animationCache = item.context.animationCache let animationCache = item.context.animationCache
supernode.addSubnode(standaloneReactionAnimation) self.addSubnode(standaloneReactionAnimation)
standaloneReactionAnimation.frame = supernode.bounds standaloneReactionAnimation.frame = self.bounds
standaloneReactionAnimation.animateReactionSelection( standaloneReactionAnimation.animateReactionSelection(
context: item.context, theme: item.theme, animationCache: animationCache, reaction: reactionItem, context: item.context, theme: item.theme, animationCache: animationCache, reaction: reactionItem,
avatarPeers: [], avatarPeers: [],
@ -250,9 +255,8 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
} }
} }
} }
}
func asyncLayout() -> (_ item: ReactionChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) { func asyncLayout() -> (_ item: ReactionChatPreviewItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
let currentNode = self.messageNode let currentNode = self.messageNode
let previousItem = self.item let previousItem = self.item
@ -280,15 +284,20 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
var attributes: [MessageAttribute] = [] var attributes: [MessageAttribute] = []
if let reaction = item.reaction { if let reaction = item.reaction {
attributes.append(ReactionsMessageAttribute(canViewList: false, reactions: [MessageReaction(value: reaction, count: 1, chosenOrder: 0)], recentPeers: [])) var recentPeers: [ReactionsMessageAttribute.RecentPeer] = []
if let accountPeer = item.accountPeer {
recentPeers.append(ReactionsMessageAttribute.RecentPeer(value: reaction, isLarge: false, isUnseen: false, isMy: true, peerId: accountPeer.id, timestamp: nil))
peers[accountPeer.id] = accountPeer
}
attributes.append(ReactionsMessageAttribute(canViewList: false, reactions: [MessageReaction(value: reaction, count: 1, chosenOrder: 0)], recentPeers: recentPeers))
} }
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: chatPeerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[userPeerId], text: messageText, attributes: attributes, media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: item.availableReactions, isCentered: true) let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: chatPeerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[userPeerId], text: messageText, attributes: attributes, media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil, backgroundNode: currentBackgroundNode, availableReactions: item.availableReactions, accountPeer: item.accountPeer, isCentered: true)
var node: ListViewItemNode? var node: ListViewItemNode?
if let current = currentNode { if let current = currentNode {
node = current node = current
messageItem.updateNode(async: { $0() }, node: { return current }, params: params, previousItem: nil, nextItem: nil, animation: .System(duration: 0.3, transition: ControlledTransition(duration: 0.3, curve: .easeInOut, interactive: false)), completion: { (layout, apply) in messageItem.updateNode(async: { $0() }, node: { return current }, params: params, previousItem: nil, nextItem: nil, animation: .System(duration: 0.4, transition: ControlledTransition(duration: 0.4, curve: .spring, interactive: false)), completion: { (layout, apply) in
let nodeFrame = CGRect(origin: current.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height)) let nodeFrame = CGRect(origin: current.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
current.contentSize = layout.contentSize current.contentSize = layout.contentSize
@ -300,6 +309,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
} else { } else {
messageItem.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { messageNode, apply in messageItem.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { messageNode, apply in
node = messageNode node = messageNode
apply().1(ListViewItemApply(isOnScreen: true)) apply().1(ListViewItemApply(isOnScreen: true))
}) })
node?.isUserInteractionEnabled = false node?.isUserInteractionEnabled = false
@ -310,14 +320,14 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
contentSize.height += node.frame.size.height contentSize.height += node.frame.size.height
} }
if item.reaction == nil { if item.reaction == nil {
contentSize.height += 34.0 //contentSize.height += 34.0
} }
insets = itemListNeighborsGroupedInsets(neighbors, params) insets = itemListNeighborsGroupedInsets(neighbors, params)
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
let layoutSize = layout.size let layoutSize = layout.size
return (layout, { [weak self] in return (layout, { [weak self] animation in
if let strongSelf = self { if let strongSelf = self {
if let previousItem = strongSelf.item, previousItem.reaction != item.reaction { if let previousItem = strongSelf.item, previousItem.reaction != item.reaction {
if let standaloneReactionAnimation = strongSelf.standaloneReactionAnimation { if let standaloneReactionAnimation = strongSelf.standaloneReactionAnimation {
@ -341,7 +351,9 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize) strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
var topOffset: CGFloat = 16.0 + 17.0 animation.animator.updateFrame(layer: strongSelf.clippingNode.layer, frame: CGRect(origin: CGPoint(), size: contentSize), completion: nil)
var topOffset: CGFloat = 16.0
if let node = node { if let node = node {
strongSelf.messageNode = node strongSelf.messageNode = node
if node.supernode == nil { if node.supernode == nil {
@ -357,17 +369,17 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
if let currentBackgroundNode = currentBackgroundNode, strongSelf.backgroundNode !== currentBackgroundNode { if let currentBackgroundNode = currentBackgroundNode, strongSelf.backgroundNode !== currentBackgroundNode {
strongSelf.backgroundNode = currentBackgroundNode strongSelf.backgroundNode = currentBackgroundNode
strongSelf.insertSubnode(currentBackgroundNode, at: 0) strongSelf.clippingNode.insertSubnode(currentBackgroundNode, at: 0)
} }
if strongSelf.topStripeNode.supernode == nil { if strongSelf.topStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) strongSelf.clippingNode.insertSubnode(strongSelf.topStripeNode, at: 1)
} }
if strongSelf.bottomStripeNode.supernode == nil { if strongSelf.bottomStripeNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) strongSelf.clippingNode.insertSubnode(strongSelf.bottomStripeNode, at: 2)
} }
if strongSelf.maskNode.supernode == nil { if strongSelf.maskNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.maskNode, at: 3) strongSelf.addSubnode(strongSelf.maskNode)
} }
let hasCorners = itemListHasRoundedBlockLayout(params) let hasCorners = itemListHasRoundedBlockLayout(params)
var hasTopCorners = false var hasTopCorners = false
@ -413,13 +425,14 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
} }
if let backgroundNode = strongSelf.backgroundNode { if let backgroundNode = strongSelf.backgroundNode {
backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0) backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: backgroundFrame.width, height: 500.0)).insetBy(dx: 0.0, dy: -100.0)
backgroundNode.update(wallpaper: item.wallpaper, animated: false) backgroundNode.update(wallpaper: item.wallpaper, animated: false)
backgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners) backgroundNode.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
backgroundNode.updateLayout(size: backgroundNode.bounds.size, displayMode: displayMode, transition: .immediate) backgroundNode.updateLayout(size: backgroundNode.bounds.size, displayMode: displayMode, transition: .immediate)
} }
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0) animation.animator.updateFrame(layer: strongSelf.maskNode.layer, frame: backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0), completion: nil)
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight)) strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight)) strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))

View File

@ -1521,7 +1521,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return presentAddMembersImpl(context: context, updatedPresentationData: updatedPresentationData, parentController: parentController, groupPeer: groupPeer, selectAddMemberDisposable: selectAddMemberDisposable, addMemberDisposable: addMemberDisposable) return presentAddMembersImpl(context: context, updatedPresentationData: updatedPresentationData, parentController: parentController, groupPeer: groupPeer, selectAddMemberDisposable: selectAddMemberDisposable, addMemberDisposable: addMemberDisposable)
} }
public func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)? = nil, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, isCentered: Bool) -> ListViewItem { public func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)? = nil, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, accountPeer: Peer?, isCentered: Bool) -> ListViewItem {
let controllerInteraction: ChatControllerInteraction let controllerInteraction: ChatControllerInteraction
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
@ -1616,7 +1616,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
chatLocation = .peer(id: messages.first!.id.peerId) chatLocation = .peer(id: messages.first!.id.peerId)
} }
return ChatMessageItemImpl(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: chatLocation, associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: false, subject: nil, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus, availableReactions: availableReactions, defaultReaction: nil, isPremium: false, accountPeer: nil, forceInlineReactions: true), controllerInteraction: controllerInteraction, content: content, disableDate: true, additionalContent: nil) return ChatMessageItemImpl(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: chatLocation, associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: false, subject: nil, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus, availableReactions: availableReactions, defaultReaction: nil, isPremium: false, accountPeer: accountPeer.flatMap(EnginePeer.init), forceInlineReactions: true), controllerInteraction: controllerInteraction, content: content, disableDate: true, additionalContent: nil)
} }
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader { public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {

View File

@ -28,6 +28,7 @@ swift_library(
"//submodules/AccountContext:AccountContext", "//submodules/AccountContext:AccountContext",
"//submodules/ComponentFlow:ComponentFlow", "//submodules/ComponentFlow:ComponentFlow",
"//submodules/AnimatedAvatarSetNode:AnimatedAvatarSetNode", "//submodules/AnimatedAvatarSetNode:AnimatedAvatarSetNode",
"//submodules/TelegramUI/Components/EmojiStatusComponent",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -35,6 +35,7 @@ public enum UndoOverlayContent {
case voiceChatFlag(text: String) case voiceChatFlag(text: String)
case voiceChatCanSpeak(text: String) case voiceChatCanSpeak(text: String)
case sticker(context: AccountContext, file: TelegramMediaFile, loop: Bool, title: String?, text: String, undoText: String?, customAction: (() -> Void)?) case sticker(context: AccountContext, file: TelegramMediaFile, loop: Bool, title: String?, text: String, undoText: String?, customAction: (() -> Void)?)
case customEmoji(context: AccountContext, file: TelegramMediaFile, loop: Bool, title: String?, text: String, undoText: String?, customAction: (() -> Void)?)
case copy(text: String) case copy(text: String)
case mediaSaved(text: String) case mediaSaved(text: String)
case paymentSent(currencyValue: String, itemTitle: String) case paymentSent(currencyValue: String, itemTitle: String)

View File

@ -17,6 +17,8 @@ import StickerResources
import AvatarNode import AvatarNode
import AccountContext import AccountContext
import AnimatedAvatarSetNode import AnimatedAvatarSetNode
import ComponentFlow
import EmojiStatusComponent
final class UndoOverlayControllerNode: ViewControllerTracingNode { final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let presentationData: PresentationData private let presentationData: PresentationData
@ -36,6 +38,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private var stillStickerNode: TransformImageNode? private var stillStickerNode: TransformImageNode?
private var stickerImageSize: CGSize? private var stickerImageSize: CGSize?
private var stickerOffset: CGPoint? private var stickerOffset: CGPoint?
private var emojiStatus: ComponentView<Empty>?
private let titleNode: ImmediateTextNode private let titleNode: ImmediateTextNode
private let textNode: ImmediateTextNode private let textNode: ImmediateTextNode
private let buttonNode: HighlightTrackingButtonNode private let buttonNode: HighlightTrackingButtonNode
@ -812,6 +815,65 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: resource._asResource(), isVideo: file.isVideoSticker), width: 80, height: 80, playbackMode: loop ? .loop : .once, mode: .cached) animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: resource._asResource(), isVideo: file.isVideoSticker), width: 80, height: 80, playbackMode: loop ? .loop : .once, mode: .cached)
} }
} }
case let .customEmoji(context, file, loop, title, text, customUndoText, _):
self.avatarNode = nil
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = nil
let imageBoundingSize = CGSize(width: 34.0, height: 34.0)
let emojiStatus = ComponentView<Empty>()
self.emojiStatus = emojiStatus
let _ = emojiStatus.update(
transition: .immediate,
component: AnyComponent(EmojiStatusComponent(
context: context,
animationCache: context.animationCache,
animationRenderer: context.animationRenderer,
content: .animation(
content: .file(file: file),
size: imageBoundingSize,
placeholderColor: UIColor(white: 1.0, alpha: 0.1),
themeColor: .white,
loopMode: loop ? .forever : .count(1)
),
isVisibleForAnimations: true,
useSharedAnimation: false,
action: nil
)),
environment: {},
containerSize: imageBoundingSize
)
self.stickerImageSize = imageBoundingSize
if let title = title {
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
} else {
self.titleNode.attributedText = nil
}
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let link = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { contents in
return ("URL", contents)
}), textAlignment: .natural)
self.textNode.attributedText = attributedText
self.textNode.maximumNumberOfLines = 5
if text.contains("](") {
isUserInteractionEnabled = true
}
if let customUndoText = customUndoText {
undoText = customUndoText
displayUndo = true
} else {
displayUndo = false
}
self.originalRemainingSeconds = isUserInteractionEnabled ? 5 : 3
case let .copy(text): case let .copy(text):
self.avatarNode = nil self.avatarNode = nil
self.iconNode = nil self.iconNode = nil
@ -1114,7 +1176,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} else { } else {
self.isUserInteractionEnabled = false self.isUserInteractionEnabled = false
} }
case .sticker: case .sticker, .customEmoji:
self.isUserInteractionEnabled = displayUndo self.isUserInteractionEnabled = displayUndo
case .dice: case .dice:
self.panelWrapperNode.clipsToBounds = true self.panelWrapperNode.clipsToBounds = true
@ -1144,6 +1206,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode.flatMap(self.panelWrapperNode.addSubnode) self.iconCheckNode.flatMap(self.panelWrapperNode.addSubnode)
self.animationNode.flatMap(self.panelWrapperNode.addSubnode) self.animationNode.flatMap(self.panelWrapperNode.addSubnode)
self.stillStickerNode.flatMap(self.panelWrapperNode.addSubnode) self.stillStickerNode.flatMap(self.panelWrapperNode.addSubnode)
if let emojiStatusView = self.emojiStatus?.view {
self.panelWrapperNode.view.addSubview(emojiStatusView)
}
self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode) self.animatedStickerNode.flatMap(self.panelWrapperNode.addSubnode)
self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode) self.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode) self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
@ -1205,6 +1270,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} else { } else {
let _ = self.action(.undo) let _ = self.action(.undo)
} }
case let .customEmoji(_, _, _, _, _, _, customAction):
if let customAction = customAction {
customAction()
} else {
let _ = self.action(.undo)
}
default: default:
let _ = self.action(.undo) let _ = self.action(.undo)
} }
@ -1434,6 +1505,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
transition.updateFrame(node: stillStickerNode, frame: iconFrame) transition.updateFrame(node: stillStickerNode, frame: iconFrame)
} }
if let emojiStatusView = self.emojiStatus?.view {
transition.updateFrame(view: emojiStatusView, frame: iconFrame)
}
if let animatedStickerNode = self.animatedStickerNode { if let animatedStickerNode = self.animatedStickerNode {
animatedStickerNode.updateLayout(size: iconFrame.size) animatedStickerNode.updateLayout(size: iconFrame.size)
transition.updateFrame(node: animatedStickerNode, frame: iconFrame) transition.updateFrame(node: animatedStickerNode, frame: iconFrame)