mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Modernize quick reaction
This commit is contained in:
parent
11b5940f07
commit
b631780d00
@ -894,7 +894,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
selectedMessages: Signal<Set<MessageId>?, NoError>,
|
||||
mode: ChatHistoryListMode
|
||||
) -> 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 makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
|
||||
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController
|
||||
|
@ -218,6 +218,12 @@ public final class ReactionIconView: PortalSourceView {
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
if !self.subviews.isEmpty {
|
||||
for subview in Array(self.subviews) {
|
||||
subview.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
self.context = nil
|
||||
self.fileId = nil
|
||||
self.file = nil
|
||||
|
@ -859,10 +859,10 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
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 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 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]
|
||||
|
||||
|
@ -116,6 +116,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen",
|
||||
"//submodules/TelegramUI/Components/Settings/PeerNameColorScreen",
|
||||
"//submodules/ManagedAnimationNode:ManagedAnimationNode",
|
||||
"//submodules/TelegramUI/Components/Settings/QuickReactionSetupController",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -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: [:])
|
||||
|
||||
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: [:])
|
||||
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 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 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: [:])
|
||||
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
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
|
@ -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 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?
|
||||
if let current = currentNode {
|
||||
|
@ -18,6 +18,7 @@ import ShareController
|
||||
import WebPBinding
|
||||
import ReactionImageComponent
|
||||
import FeaturedStickersScreen
|
||||
import QuickReactionSetupController
|
||||
|
||||
private final class InstalledStickerPacksControllerArguments {
|
||||
let context: AccountContext
|
||||
|
@ -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: [:])
|
||||
|
||||
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: [:])
|
||||
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 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 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: [:])
|
||||
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
|
||||
if case .regular = layout.metrics.widthClass {
|
||||
|
@ -1077,7 +1077,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
return state
|
||||
}, animated: true)
|
||||
}, clickThroughMessage: {
|
||||
}, backgroundNode: self.backgroundNode, availableReactions: nil, isCentered: false)
|
||||
}, backgroundNode: self.backgroundNode, availableReactions: nil, accountPeer: nil, isCentered: false)
|
||||
return item
|
||||
}
|
||||
|
||||
|
@ -617,7 +617,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
sampleMessages.append(message8)
|
||||
|
||||
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
|
||||
|
@ -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: [:])
|
||||
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] = []
|
||||
|
@ -1580,17 +1580,17 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
||||
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: [:])
|
||||
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: [:])
|
||||
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 {
|
||||
let attributedText = convertMarkdownToAttributes(NSAttributedString(string: serviceMessageText))
|
||||
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: [:])
|
||||
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)
|
||||
|
@ -1373,5 +1373,5 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public func shouldDisplayInlineDateReactions(message: Message, isPremium: Bool, forceInline: Bool) -> Bool {
|
||||
return forceInline
|
||||
return false
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ swift_library(
|
||||
"//submodules/PremiumUI",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/TextFormat",
|
||||
"//submodules/Components/HierarchyTrackingLayer",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -7,6 +7,47 @@ import ComponentDisplayAdapters
|
||||
import SwitchComponent
|
||||
import EntityKeyboard
|
||||
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 {
|
||||
let context: AccountContext
|
||||
@ -66,10 +107,10 @@ final class EmojiListInputComponent: Component {
|
||||
|
||||
private var itemLayers: [Int64: EmojiPagerContentComponent.View.ItemLayer] = [:]
|
||||
private let trailingPlaceholder = ComponentView<Empty>()
|
||||
private let caretIndicator: UIImageView
|
||||
private let caretIndicator: CaretIndicatorView
|
||||
|
||||
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
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
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 {
|
||||
let verticalInset: CGFloat = 12.0
|
||||
let placeholderSpacing: CGFloat = 6.0
|
||||
@ -136,6 +185,10 @@ final class EmojiListInputComponent: Component {
|
||||
var rowCount = (component.reactionItems.count + (itemsPerRow - 1)) / itemsPerRow
|
||||
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.state = state
|
||||
|
||||
@ -174,9 +227,7 @@ final class EmojiListInputComponent: Component {
|
||||
self.caretIndicator.tintColor = component.theme.list.itemAccentColor
|
||||
self.caretIndicator.isHidden = !component.isInputActive
|
||||
|
||||
if component.caretPosition >= component.reactionItems.count {
|
||||
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 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))
|
||||
|
||||
var validIds: [Int64] = []
|
||||
for i in 0 ..< component.reactionItems.count {
|
||||
@ -205,7 +256,7 @@ final class EmojiListInputComponent: Component {
|
||||
itemFile: item.file,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: .none
|
||||
tintMode: item.file.isCustomTemplateEmoji ? .primary : .none
|
||||
),
|
||||
context: component.context,
|
||||
attemptSynchronousLoad: false,
|
||||
@ -214,7 +265,7 @@ final class EmojiListInputComponent: Component {
|
||||
renderer: component.context.animationRenderer,
|
||||
placeholderColor: component.theme.list.mediaPlaceholderColor,
|
||||
blurredBadgeColor: .clear,
|
||||
accentIconColor: component.theme.list.itemAccentColor,
|
||||
accentIconColor: component.theme.list.itemPrimaryTextColor,
|
||||
pointSize: CGSize(width: 32.0, height: 32.0),
|
||||
onUpdateDisplayPlaceholder: { _, _ in
|
||||
}
|
||||
@ -224,10 +275,19 @@ final class EmojiListInputComponent: Component {
|
||||
}
|
||||
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)
|
||||
|
||||
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 {
|
||||
@ -255,6 +315,22 @@ final class EmojiListInputComponent: Component {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import ComponentDisplayAdapters
|
||||
import EntityKeyboard
|
||||
import AccountContext
|
||||
import PagerComponent
|
||||
import AudioToolbox
|
||||
|
||||
public final class EmojiSelectionComponent: Component {
|
||||
public typealias EnvironmentType = Empty
|
||||
@ -89,8 +90,8 @@ public final class EmojiSelectionComponent: Component {
|
||||
private let shadowView: UIImageView
|
||||
private let cornersView: UIImageView
|
||||
|
||||
private let backspaceButton = ComponentView<Empty>()
|
||||
private let backspaceBackgroundView: UIImageView
|
||||
private let backspaceButtonView: HighlightTrackingButton
|
||||
|
||||
private var component: EmojiSelectionComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
@ -105,7 +106,6 @@ public final class EmojiSelectionComponent: Component {
|
||||
self.cornersView = UIImageView()
|
||||
|
||||
self.backspaceBackgroundView = UIImageView()
|
||||
self.backspaceButtonView = HighlightTrackingButton()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
@ -116,9 +116,6 @@ public final class EmojiSelectionComponent: Component {
|
||||
self.addSubview(self.cornersView)
|
||||
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
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
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.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)
|
||||
|
||||
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) {
|
||||
@ -176,10 +144,6 @@ public final class EmojiSelectionComponent: Component {
|
||||
deinit {
|
||||
}
|
||||
|
||||
@objc private func backspacePressed() {
|
||||
self.component?.backspace?()
|
||||
}
|
||||
|
||||
func update(component: EmojiSelectionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||
self.backgroundColor = component.backgroundColor
|
||||
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 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 {
|
||||
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))
|
||||
@ -215,14 +202,22 @@ public final class EmojiSelectionComponent: Component {
|
||||
}
|
||||
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)
|
||||
transition.setPosition(view: self.backspaceButtonView, position: backspaceButtonFrame.center)
|
||||
transition.setBounds(view: self.backspaceButtonView, bounds: CGRect(origin: CGPoint(), size: backspaceButtonFrame.size))
|
||||
if component.backspace != nil {
|
||||
transition.setAlpha(view: self.backspaceButtonView, alpha: 1.0)
|
||||
transition.setScale(view: self.backspaceButtonView, scale: 1.0)
|
||||
} else {
|
||||
transition.setAlpha(view: self.backspaceButtonView, alpha: 0.0)
|
||||
transition.setScale(view: self.backspaceButtonView, scale: 0.001)
|
||||
|
||||
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 {
|
||||
transition.setAlpha(view: backspaceButtonView, alpha: 1.0)
|
||||
transition.setScale(view: backspaceButtonView, scale: 1.0)
|
||||
} else {
|
||||
transition.setAlpha(view: backspaceButtonView, alpha: 0.0)
|
||||
transition.setScale(view: backspaceButtonView, scale: 0.001)
|
||||
}
|
||||
}
|
||||
|
||||
let keyboardSize = self.keyboardView.update(
|
||||
@ -233,7 +228,7 @@ public final class EmojiSelectionComponent: Component {
|
||||
isContentInFocus: false,
|
||||
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),
|
||||
emojiContent: component.emojiContent,
|
||||
emojiContent: component.emojiContent.withCustomTintColor(component.theme.list.itemPrimaryTextColor),
|
||||
stickerContent: nil,
|
||||
maskContent: nil,
|
||||
gifContent: nil,
|
||||
|
@ -19,6 +19,7 @@ import UndoUI
|
||||
import BundleIconComponent
|
||||
import AnimatedTextComponent
|
||||
import TextFormat
|
||||
import AudioToolbox
|
||||
|
||||
private final class ButtonSubtitleComponent: CombinedComponent {
|
||||
let count: Int
|
||||
@ -136,6 +137,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
private var caretPosition: Int?
|
||||
|
||||
private var displayInput: Bool = false
|
||||
private var recenterOnCaret: Bool = false
|
||||
|
||||
private var isApplyingSettings: Bool = false
|
||||
private var applyDisposable: Disposable?
|
||||
@ -209,14 +211,14 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
} else {
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
//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
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -446,12 +448,30 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
|
||||
if let index = enabledReactions.firstIndex(where: { $0.file.fileId.id == itemFile.fileId.id }) {
|
||||
enabledReactions.remove(at: index)
|
||||
if let caretPosition = self.caretPosition, caretPosition > index {
|
||||
self.caretPosition = max(0, caretPosition - 1)
|
||||
}
|
||||
} 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
|
||||
if let availableReactions = self.availableReactions, let reactionItem = availableReactions.reactions.first(where: { $0.selectAnimation.fileId.id == itemFile.fileId.id }) {
|
||||
reaction = reactionItem.value
|
||||
@ -479,7 +499,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
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.environment?.controller()?.present(undoController, in: .current)
|
||||
}
|
||||
@ -494,6 +514,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
enabledReactions.append(item)
|
||||
self.caretPosition = enabledReactions.count
|
||||
}
|
||||
self.recenterOnCaret = true
|
||||
}
|
||||
self.enabledReactions = enabledReactions
|
||||
if !self.isUpdating {
|
||||
@ -707,6 +728,7 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
}
|
||||
if self.emojiContent != nil && !self.displayInput {
|
||||
self.displayInput = true
|
||||
self.recenterOnCaret = true
|
||||
self.state?.updated(transition: .spring(duration: 0.5))
|
||||
}
|
||||
},
|
||||
@ -936,10 +958,12 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
if caretPosition > 0 {
|
||||
enabledReactions.remove(at: caretPosition - 1)
|
||||
self.caretPosition = caretPosition - 1
|
||||
self.recenterOnCaret = true
|
||||
}
|
||||
} else {
|
||||
enabledReactions.removeLast()
|
||||
self.caretPosition = enabledReactions.count
|
||||
self.recenterOnCaret = true
|
||||
}
|
||||
self.enabledReactions = enabledReactions
|
||||
if !self.isUpdating {
|
||||
@ -1007,6 +1031,25 @@ final class PeerAllowedReactionsScreenComponent: Component {
|
||||
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)
|
||||
|
||||
return availableSize
|
||||
@ -1077,6 +1120,9 @@ public class PeerAllowedReactionsScreen: ViewControllerComponentContainer {
|
||||
initialContent: initialContent
|
||||
), navigationBarAppearance: .default, theme: .default)
|
||||
|
||||
//TODO:localize
|
||||
self.title = "Reactions"
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
guard let self, let componentView = self.node.hostView.componentView as? PeerAllowedReactionsScreenComponent.View else {
|
||||
return
|
||||
|
@ -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: [:])
|
||||
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] = []
|
||||
|
@ -18,15 +18,18 @@ private final class PeerNameColorScreenArguments {
|
||||
let context: AccountContext
|
||||
let updateNameColor: (PeerNameColor?) -> Void
|
||||
let updateBackgroundEmojiId: (Int64?) -> Void
|
||||
let resetColor: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
updateNameColor: @escaping (PeerNameColor?) -> Void,
|
||||
updateBackgroundEmojiId: @escaping (Int64?) -> Void
|
||||
updateBackgroundEmojiId: @escaping (Int64?) -> Void,
|
||||
resetColor: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.updateNameColor = updateNameColor
|
||||
self.updateBackgroundEmojiId = updateBackgroundEmojiId
|
||||
self.resetColor = resetColor
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +216,7 @@ private enum PeerNameColorScreenEntry: ItemListNodeEntry {
|
||||
case .removeColor:
|
||||
//TODO:localize
|
||||
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):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
@ -447,6 +450,19 @@ public func PeerNameColorScreen(
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -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",
|
||||
],
|
||||
)
|
@ -46,7 +46,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
}
|
||||
|
||||
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 quickReaction(String, MessageReaction.Reaction, AvailableReactions)
|
||||
case quickReactionDescription(String)
|
||||
@ -98,8 +98,8 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .demoMessage(lhsWallpaper, lhsFontSize, lhsBubbleCorners, lhsDateTimeFormat, lhsNameDisplayOrder, lhsAvailableReactions, lhsReaction):
|
||||
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 {
|
||||
case let .demoMessage(lhsWallpaper, lhsFontSize, lhsBubbleCorners, lhsDateTimeFormat, lhsNameDisplayOrder, lhsAvailableReactions, lhsReaction, lhsAccountPeer):
|
||||
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
|
||||
} else {
|
||||
return false
|
||||
@ -134,7 +134,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case let .demoHeader(text):
|
||||
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(
|
||||
context: arguments.context,
|
||||
theme: presentationData.theme,
|
||||
@ -147,6 +147,7 @@ private enum QuickReactionSetupControllerEntry: ItemListNodeEntry {
|
||||
nameDisplayOrder: nameDisplayOrder,
|
||||
availableReactions: availableReactions,
|
||||
reaction: reaction,
|
||||
accountPeer: accountPeer,
|
||||
toggleReaction: {
|
||||
arguments.toggleReaction()
|
||||
}
|
||||
@ -172,7 +173,8 @@ private func quickReactionSetupControllerEntries(
|
||||
availableReactions: AvailableReactions?,
|
||||
reactionSettings: ReactionSettings,
|
||||
state: QuickReactionSetupControllerState,
|
||||
isPremium: Bool
|
||||
isPremium: Bool,
|
||||
accountPeer: Peer?
|
||||
) -> [QuickReactionSetupControllerEntry] {
|
||||
var entries: [QuickReactionSetupControllerEntry] = []
|
||||
|
||||
@ -185,7 +187,8 @@ private func quickReactionSetupControllerEntries(
|
||||
dateTimeFormat: presentationData.dateTimeFormat,
|
||||
nameDisplayOrder: presentationData.nameDisplayOrder,
|
||||
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))
|
||||
|
||||
@ -257,7 +260,8 @@ public func quickReactionSetupController(
|
||||
availableReactions: availableReactions,
|
||||
reactionSettings: settings,
|
||||
state: state,
|
||||
isPremium: isPremium
|
||||
isPremium: isPremium,
|
||||
accountPeer: accountPeer?._asPeer()
|
||||
)
|
||||
|
||||
let controllerState = ItemListControllerState(
|
||||
@ -283,16 +287,7 @@ public func quickReactionSetupController(
|
||||
|
||||
let controller = ItemListController(context: context, state: signal)
|
||||
|
||||
controller.didScrollWithOffset = { [weak controller] offset, transition, _, _ in
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.alwaysSynchronous = true
|
||||
|
||||
openQuickReactionImpl = { [weak controller] in
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
@ -26,9 +26,10 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
||||
let nameDisplayOrder: PresentationPersonNameOrder
|
||||
let availableReactions: AvailableReactions?
|
||||
let reaction: MessageReaction.Reaction?
|
||||
let accountPeer: Peer?
|
||||
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.theme = theme
|
||||
self.strings = strings
|
||||
@ -40,6 +41,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
self.availableReactions = availableReactions
|
||||
self.reaction = reaction
|
||||
self.accountPeer = accountPeer
|
||||
self.toggleReaction = toggleReaction
|
||||
}
|
||||
|
||||
@ -53,7 +55,7 @@ class ReactionChatPreviewItem: ListViewItem, ItemListItem {
|
||||
|
||||
Queue.mainQueue().async {
|
||||
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))
|
||||
Queue.mainQueue().async {
|
||||
completion(layout, { _ in
|
||||
apply()
|
||||
apply(animation)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -83,6 +85,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let clippingNode: ASDisplayNode
|
||||
private let containerNode: ASDisplayNode
|
||||
|
||||
private var messageNode: ListViewItemNode?
|
||||
@ -104,14 +107,17 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
self.clippingNode = ASDisplayNode()
|
||||
self.clippingNode.clipsToBounds = true
|
||||
self.clippingNode.layer.cornerRadius = 10.0
|
||||
|
||||
self.containerNode = ASDisplayNode()
|
||||
self.containerNode.subnodeTransform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.addSubnode(self.containerNode)
|
||||
self.addSubnode(self.clippingNode)
|
||||
self.clippingNode.addSubnode(self.containerNode)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -227,32 +233,30 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
self.standaloneReactionAnimation = nil
|
||||
}
|
||||
|
||||
if let supernode = self.supernode {
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect)
|
||||
self.loadNextGenericReactionEffect(context: item.context)
|
||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||
|
||||
let animationCache = item.context.animationCache
|
||||
|
||||
supernode.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = supernode.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: item.context, theme: item.theme, animationCache: animationCache, reaction: reactionItem,
|
||||
avatarPeers: [],
|
||||
playHaptic: false,
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: nil,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.genericReactionEffect)
|
||||
self.loadNextGenericReactionEffect(context: item.context)
|
||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||
|
||||
let animationCache = item.context.animationCache
|
||||
|
||||
self.addSubnode(standaloneReactionAnimation)
|
||||
standaloneReactionAnimation.frame = self.bounds
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: item.context, theme: item.theme, animationCache: animationCache, reaction: reactionItem,
|
||||
avatarPeers: [],
|
||||
playHaptic: false,
|
||||
isLarge: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: nil,
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 previousItem = self.item
|
||||
@ -280,15 +284,20 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
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?
|
||||
if let current = currentNode {
|
||||
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))
|
||||
|
||||
current.contentSize = layout.contentSize
|
||||
@ -300,6 +309,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
} else {
|
||||
messageItem.nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: false, previousItem: nil, nextItem: nil, completion: { messageNode, apply in
|
||||
node = messageNode
|
||||
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
node?.isUserInteractionEnabled = false
|
||||
@ -310,14 +320,14 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
contentSize.height += node.frame.size.height
|
||||
}
|
||||
if item.reaction == nil {
|
||||
contentSize.height += 34.0
|
||||
//contentSize.height += 34.0
|
||||
}
|
||||
insets = itemListNeighborsGroupedInsets(neighbors, params)
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||
let layoutSize = layout.size
|
||||
|
||||
return (layout, { [weak self] in
|
||||
return (layout, { [weak self] animation in
|
||||
if let strongSelf = self {
|
||||
if let previousItem = strongSelf.item, previousItem.reaction != item.reaction {
|
||||
if let standaloneReactionAnimation = strongSelf.standaloneReactionAnimation {
|
||||
@ -341,7 +351,9 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
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 {
|
||||
strongSelf.messageNode = node
|
||||
if node.supernode == nil {
|
||||
@ -357,17 +369,17 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
if let currentBackgroundNode = currentBackgroundNode, strongSelf.backgroundNode !== currentBackgroundNode {
|
||||
strongSelf.backgroundNode = currentBackgroundNode
|
||||
strongSelf.insertSubnode(currentBackgroundNode, at: 0)
|
||||
strongSelf.clippingNode.insertSubnode(currentBackgroundNode, at: 0)
|
||||
}
|
||||
|
||||
if strongSelf.topStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||
strongSelf.clippingNode.insertSubnode(strongSelf.topStripeNode, at: 1)
|
||||
}
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
strongSelf.clippingNode.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
strongSelf.addSubnode(strongSelf.maskNode)
|
||||
}
|
||||
let hasCorners = itemListHasRoundedBlockLayout(params)
|
||||
var hasTopCorners = false
|
||||
@ -413,13 +425,14 @@ class ReactionChatPreviewItemNode: ListViewItemNode {
|
||||
}
|
||||
|
||||
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.updateBubbleTheme(bubbleTheme: item.theme, bubbleCorners: item.chatBubbleCorners)
|
||||
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.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||
|
@ -1521,7 +1521,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
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
|
||||
|
||||
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
|
||||
@ -1616,7 +1616,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
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 {
|
||||
|
@ -28,6 +28,7 @@ swift_library(
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/ComponentFlow:ComponentFlow",
|
||||
"//submodules/AnimatedAvatarSetNode:AnimatedAvatarSetNode",
|
||||
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -35,6 +35,7 @@ public enum UndoOverlayContent {
|
||||
case voiceChatFlag(text: String)
|
||||
case voiceChatCanSpeak(text: String)
|
||||
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 mediaSaved(text: String)
|
||||
case paymentSent(currencyValue: String, itemTitle: String)
|
||||
|
@ -17,6 +17,8 @@ import StickerResources
|
||||
import AvatarNode
|
||||
import AccountContext
|
||||
import AnimatedAvatarSetNode
|
||||
import ComponentFlow
|
||||
import EmojiStatusComponent
|
||||
|
||||
final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private let presentationData: PresentationData
|
||||
@ -36,6 +38,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
private var stillStickerNode: TransformImageNode?
|
||||
private var stickerImageSize: CGSize?
|
||||
private var stickerOffset: CGPoint?
|
||||
private var emojiStatus: ComponentView<Empty>?
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
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)
|
||||
}
|
||||
}
|
||||
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):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
@ -1114,7 +1176,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
} else {
|
||||
self.isUserInteractionEnabled = false
|
||||
}
|
||||
case .sticker:
|
||||
case .sticker, .customEmoji:
|
||||
self.isUserInteractionEnabled = displayUndo
|
||||
case .dice:
|
||||
self.panelWrapperNode.clipsToBounds = true
|
||||
@ -1144,6 +1206,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
self.iconCheckNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.animationNode.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.slotMachineNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
self.avatarNode.flatMap(self.panelWrapperNode.addSubnode)
|
||||
@ -1205,6 +1270,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
} else {
|
||||
let _ = self.action(.undo)
|
||||
}
|
||||
case let .customEmoji(_, _, _, _, _, _, customAction):
|
||||
if let customAction = customAction {
|
||||
customAction()
|
||||
} else {
|
||||
let _ = self.action(.undo)
|
||||
}
|
||||
default:
|
||||
let _ = self.action(.undo)
|
||||
}
|
||||
@ -1434,6 +1505,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
transition.updateFrame(node: stillStickerNode, frame: iconFrame)
|
||||
}
|
||||
|
||||
if let emojiStatusView = self.emojiStatus?.view {
|
||||
transition.updateFrame(view: emojiStatusView, frame: iconFrame)
|
||||
}
|
||||
|
||||
if let animatedStickerNode = self.animatedStickerNode {
|
||||
animatedStickerNode.updateLayout(size: iconFrame.size)
|
||||
transition.updateFrame(node: animatedStickerNode, frame: iconFrame)
|
||||
|
Loading…
x
Reference in New Issue
Block a user