mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Send message effects
This commit is contained in:
parent
18a6a3c2a9
commit
16faaa4575
@ -1097,6 +1097,7 @@ public protocol AccountContext: AnyObject {
|
||||
var animatedEmojiStickersValue: [String: [StickerPackItem]] { get }
|
||||
var additionalAnimatedEmojiStickers: Signal<[String: [Int: StickerPackItem]], NoError> { get }
|
||||
var availableReactions: Signal<AvailableReactions?, NoError> { get }
|
||||
var availableMessageEffects: Signal<AvailableMessageEffects?, NoError> { get }
|
||||
|
||||
var isPremium: Bool { get }
|
||||
var userLimits: EngineConfiguration.UserLimits { get }
|
||||
|
@ -44,6 +44,7 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
public let currentlyPlayingMessageId: EngineMessage.Index?
|
||||
public let isCopyProtectionEnabled: Bool
|
||||
public let availableReactions: AvailableReactions?
|
||||
public let availableMessageEffects: AvailableMessageEffects?
|
||||
public let savedMessageTags: SavedMessageTags?
|
||||
public let defaultReaction: MessageReaction.Reaction?
|
||||
public let isPremium: Bool
|
||||
@ -75,6 +76,7 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
currentlyPlayingMessageId: EngineMessage.Index? = nil,
|
||||
isCopyProtectionEnabled: Bool = false,
|
||||
availableReactions: AvailableReactions?,
|
||||
availableMessageEffects: AvailableMessageEffects?,
|
||||
savedMessageTags: SavedMessageTags?,
|
||||
defaultReaction: MessageReaction.Reaction?,
|
||||
isPremium: Bool,
|
||||
@ -105,6 +107,7 @@ public final class ChatMessageItemAssociatedData: Equatable {
|
||||
self.currentlyPlayingMessageId = currentlyPlayingMessageId
|
||||
self.isCopyProtectionEnabled = isCopyProtectionEnabled
|
||||
self.availableReactions = availableReactions
|
||||
self.availableMessageEffects = availableMessageEffects
|
||||
self.savedMessageTags = savedMessageTags
|
||||
self.defaultReaction = defaultReaction
|
||||
self.isPremium = isPremium
|
||||
|
@ -943,8 +943,8 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputNode.textView, attachment: true, canSendWhenOnline: sendWhenOnlineAvailable, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode in
|
||||
let controller = makeChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputNode.textView, emojiViewProvider: textInputPanelNode.emojiViewProvider, attachment: true, canSendWhenOnline: sendWhenOnlineAvailable, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode, _ in
|
||||
switch mode {
|
||||
case .generic:
|
||||
textInputPanelNode?.sendMessage(.generic)
|
||||
@ -953,10 +953,9 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate {
|
||||
case .whenOnline:
|
||||
textInputPanelNode?.sendMessage(.whenOnline)
|
||||
}
|
||||
}, schedule: { [weak textInputPanelNode] in
|
||||
}, schedule: { [weak textInputPanelNode] _ in
|
||||
textInputPanelNode?.sendMessage(.schedule)
|
||||
})
|
||||
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||
strongSelf.presentInGlobalOverlay(controller)
|
||||
})
|
||||
}, openScheduledMessages: {
|
||||
|
@ -493,7 +493,7 @@ public final class CallListController: TelegramBaseController {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Calls_StartNewCall, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
return filters
|
||||
}
|
||||
|> deliverOnMainQueue).startStandalone(completed: {
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
chatListController?.present(UndoOverlayController(presentationData: presentationData, content: .chatRemovedFromFolder(chatTitle: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), folderTitle: title), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
return false
|
||||
}), in: .current)
|
||||
@ -275,7 +275,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: imageName), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let isPremium = limitsData.0?.isPremium ?? false
|
||||
let (_, limits, premiumLimits) = limitsData
|
||||
|
||||
@ -330,10 +330,10 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
|
||||
c.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil, animated: true)
|
||||
c?.setItems(.single(ContextController.Items(content: .list(updatedItems))), minHeight: nil, animated: true)
|
||||
})))
|
||||
}
|
||||
}
|
||||
@ -624,7 +624,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
|
||||
/*subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)*/
|
||||
|
||||
@ -657,8 +657,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
|
||||
}
|
||||
})))
|
||||
|
||||
//c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c.setItems(.single(ContextController.Items(content: .list(subItems))), minHeight: nil, animated: true)
|
||||
c?.setItems(.single(ContextController.Items(content: .list(subItems))), minHeight: nil, animated: true)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
@ -813,7 +812,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
|
||||
], title: nil, text: presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
})))
|
||||
|
||||
c.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil, animated: true)
|
||||
c?.setItems(.single(ContextController.Items(content: .list(items))), minHeight: nil, animated: true)
|
||||
}
|
||||
})))
|
||||
|
||||
|
@ -1592,7 +1592,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_EditFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1635,7 +1635,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_AddChatsToFolder, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1728,7 +1728,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ReadAll, textColor: .primary, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReadAll"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1743,7 +1743,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: filterPeersAreMuted.areMuted ? strongSelf.presentationData.strings.ChatList_ContextUnmuteAll : strongSelf.presentationData.strings.ChatList_ContextMuteAll, textColor: .primary, badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: filterPeersAreMuted.areMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
})
|
||||
|
||||
guard let strongSelf = self else {
|
||||
@ -1786,7 +1786,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ContextMenuShare, textColor: .primary, badge: data.hasSharedLinks ? nil : ContextMenuActionBadge(value: strongSelf.presentationData.strings.ChatList_ContextMenuBadgeNew, color: .accent, style: .label), icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1807,7 +1807,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_RemoveFolder, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1819,7 +1819,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_EditFolders, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -1833,7 +1833,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.ChatList_ReorderTabs, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -2893,7 +2893,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryFeed_ContextAddStory, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2905,7 +2905,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryFeed_ContextSavedStories, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Stories"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2917,7 +2917,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryFeed_ContextArchivedStories, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2939,7 +2939,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: openTitle, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: openIcon), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -3008,7 +3008,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryFeed_ContextOpenChat, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MessageBubble"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self, let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
@ -3020,7 +3020,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryFeed_ContextOpenProfile, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -5705,7 +5705,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
items.append(.action(ContextMenuActionItem(text: presetList.isEmpty ? strongSelf.presentationData.strings.ChatList_AddFolder : strongSelf.presentationData.strings.ChatList_EditFolders, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: presetList.isEmpty ? "Chat/Context Menu/Add" : "Chat/Context Menu/ItemList"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -1026,7 +1026,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), nil, message.id, false)
|
||||
})
|
||||
})))
|
||||
@ -1036,7 +1036,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
items.append(.separator)
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismissInput()
|
||||
|
||||
@ -1087,7 +1087,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
|
||||
if let linkForCopying = linkForCopying {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {})
|
||||
c?.dismiss(completion: {})
|
||||
UIPasteboard.general.string = linkForCopying
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -1097,7 +1097,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
|
||||
if !message._asMessage().isCopyProtected() {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.forwardMessages(messageIds: Set([message.id]))
|
||||
}
|
||||
@ -1105,14 +1105,14 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.threadId, message.id, false)
|
||||
})
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismissInput()
|
||||
|
||||
@ -1151,7 +1151,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
self?.openMessage(EnginePeer(message.peers[message.id.peerId]!), message.threadId, message.id, false)
|
||||
})
|
||||
})))
|
||||
@ -1160,7 +1160,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.forwardMessages(messageIds: [message.id])
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ swift_library(
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
@ -24,6 +25,13 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/EntityKeyboard",
|
||||
"//submodules/ReactionSelectionNode",
|
||||
"//submodules/Components/ReactionButtonListComponent",
|
||||
"//submodules/Components/ViewControllerComponent",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/ChatMessageBackground",
|
||||
"//submodules/WallpaperBackgroundNode",
|
||||
"//submodules/Components/MultilineTextWithEntitiesComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -9,13 +9,28 @@ import ContextUI
|
||||
import TelegramCore
|
||||
import TextFormat
|
||||
import ReactionSelectionNode
|
||||
import WallpaperBackgroundNode
|
||||
|
||||
public final class ChatSendMessageActionSheetController: ViewController {
|
||||
public enum SendMode {
|
||||
case generic
|
||||
case silently
|
||||
case whenOnline
|
||||
public enum ChatSendMessageActionSheetControllerSendMode {
|
||||
case generic
|
||||
case silently
|
||||
case whenOnline
|
||||
}
|
||||
|
||||
public final class ChatSendMessageActionSheetControllerMessageEffect {
|
||||
public let id: Int64
|
||||
|
||||
public init(id: Int64) {
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
public protocol ChatSendMessageActionSheetController: ViewController {
|
||||
typealias SendMode = ChatSendMessageActionSheetControllerSendMode
|
||||
typealias MessageEffect = ChatSendMessageActionSheetControllerMessageEffect
|
||||
}
|
||||
|
||||
private final class ChatSendMessageActionSheetControllerImpl: ViewController, ChatSendMessageActionSheetController {
|
||||
private var controllerNode: ChatSendMessageActionSheetControllerNode {
|
||||
return self.displayNode as! ChatSendMessageActionSheetControllerNode
|
||||
}
|
||||
@ -33,8 +48,8 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
private let attachment: Bool
|
||||
private let canSendWhenOnline: Bool
|
||||
private let completion: () -> Void
|
||||
private let sendMessage: (SendMode) -> Void
|
||||
private let schedule: () -> Void
|
||||
private let sendMessage: (SendMode, MessageEffect?) -> Void
|
||||
private let schedule: (MessageEffect?) -> Void
|
||||
private let reactionItems: [ReactionItem]?
|
||||
|
||||
private var presentationData: PresentationData
|
||||
@ -46,9 +61,9 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
private let emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, isScheduledMessages: Bool = false, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputView: UITextView, attachment: Bool = false, canSendWhenOnline: Bool, completion: @escaping () -> Void, sendMessage: @escaping (SendMode) -> Void, schedule: @escaping () -> Void, reactionItems: [ReactionItem]? = nil) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, isScheduledMessages: Bool = false, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputView: UITextView, emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?, attachment: Bool = false, canSendWhenOnline: Bool, completion: @escaping () -> Void, sendMessage: @escaping (SendMode, MessageEffect?) -> Void, schedule: @escaping (MessageEffect?) -> Void, reactionItems: [ReactionItem]? = nil) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
@ -57,6 +72,7 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
self.gesture = gesture
|
||||
self.sourceSendButton = sourceSendButton
|
||||
self.textInputView = textInputView
|
||||
self.emojiViewProvider = emojiViewProvider
|
||||
self.attachment = attachment
|
||||
self.canSendWhenOnline = canSendWhenOnline
|
||||
self.completion = completion
|
||||
@ -111,16 +127,32 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
}
|
||||
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputView: self.textInputView, attachment: self.attachment, canSendWhenOnline: self.canSendWhenOnline, forwardedCount: forwardedCount, hasEntityKeyboard: self.hasEntityKeyboard, emojiViewProvider: self.emojiViewProvider, send: { [weak self] in
|
||||
self?.sendMessage(.generic)
|
||||
var messageEffect: MessageEffect?
|
||||
if let selectedEffect = self?.controllerNode.selectedMessageEffect {
|
||||
messageEffect = MessageEffect(id: selectedEffect.id)
|
||||
}
|
||||
self?.sendMessage(.generic, messageEffect)
|
||||
self?.dismiss(cancel: false)
|
||||
}, sendSilently: { [weak self] in
|
||||
self?.sendMessage(.silently)
|
||||
var messageEffect: MessageEffect?
|
||||
if let selectedEffect = self?.controllerNode.selectedMessageEffect {
|
||||
messageEffect = MessageEffect(id: selectedEffect.id)
|
||||
}
|
||||
self?.sendMessage(.silently, messageEffect)
|
||||
self?.dismiss(cancel: false)
|
||||
}, sendWhenOnline: { [weak self] in
|
||||
self?.sendMessage(.whenOnline)
|
||||
var messageEffect: MessageEffect?
|
||||
if let selectedEffect = self?.controllerNode.selectedMessageEffect {
|
||||
messageEffect = MessageEffect(id: selectedEffect.id)
|
||||
}
|
||||
self?.sendMessage(.whenOnline, messageEffect)
|
||||
self?.dismiss(cancel: false)
|
||||
}, schedule: !canSchedule ? nil : { [weak self] in
|
||||
self?.schedule()
|
||||
var messageEffect: MessageEffect?
|
||||
if let selectedEffect = self?.controllerNode.selectedMessageEffect {
|
||||
messageEffect = MessageEffect(id: selectedEffect.id)
|
||||
}
|
||||
self?.schedule(messageEffect)
|
||||
self?.dismiss(cancel: false)
|
||||
}, cancel: { [weak self] in
|
||||
self?.dismiss(cancel: true)
|
||||
@ -160,3 +192,64 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func makeChatSendMessageActionSheetController(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
peerId: EnginePeer.Id?,
|
||||
isScheduledMessages: Bool = false,
|
||||
forwardMessageIds: [EngineMessage.Id]?,
|
||||
hasEntityKeyboard: Bool,
|
||||
gesture: ContextGesture,
|
||||
sourceSendButton: ASDisplayNode,
|
||||
textInputView: UITextView,
|
||||
emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?,
|
||||
wallpaperBackgroundNode: WallpaperBackgroundNode? = nil,
|
||||
attachment: Bool = false,
|
||||
canSendWhenOnline: Bool,
|
||||
completion: @escaping () -> Void,
|
||||
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
schedule: @escaping (ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
reactionItems: [ReactionItem]? = nil
|
||||
) -> ChatSendMessageActionSheetController {
|
||||
if textInputView.text.isEmpty {
|
||||
return ChatSendMessageActionSheetControllerImpl(
|
||||
context: context,
|
||||
updatedPresentationData: updatedPresentationData,
|
||||
peerId: peerId,
|
||||
isScheduledMessages: isScheduledMessages,
|
||||
forwardMessageIds: forwardMessageIds,
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
sourceSendButton: sourceSendButton,
|
||||
textInputView: textInputView,
|
||||
emojiViewProvider: emojiViewProvider,
|
||||
attachment: attachment,
|
||||
canSendWhenOnline: canSendWhenOnline,
|
||||
completion: completion,
|
||||
sendMessage: sendMessage,
|
||||
schedule: schedule,
|
||||
reactionItems: reactionItems
|
||||
)
|
||||
}
|
||||
|
||||
return ChatSendMessageContextScreen(
|
||||
context: context,
|
||||
updatedPresentationData: updatedPresentationData,
|
||||
peerId: peerId,
|
||||
isScheduledMessages: isScheduledMessages,
|
||||
forwardMessageIds: forwardMessageIds,
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
sourceSendButton: sourceSendButton,
|
||||
textInputView: textInputView,
|
||||
emojiViewProvider: emojiViewProvider,
|
||||
wallpaperBackgroundNode: wallpaperBackgroundNode,
|
||||
attachment: attachment,
|
||||
canSendWhenOnline: canSendWhenOnline,
|
||||
completion: completion,
|
||||
sendMessage: sendMessage,
|
||||
schedule: schedule,
|
||||
reactionItems: reactionItems
|
||||
)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
@ -186,9 +187,10 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
private let toMessageTextScrollView: UIScrollView
|
||||
private let toMessageTextNode: ChatInputTextNode
|
||||
private var messageEffectReactionIcon: ReactionIconView?
|
||||
private var messageEffectReactionText: ImmediateTextView?
|
||||
private let scrollNode: ASScrollNode
|
||||
|
||||
private var selectedMessageEffect: (reaction: MessageReaction.Reaction, file: TelegramMediaFile)?
|
||||
private(set) var selectedMessageEffect: (id: Int64, effect: AvailableMessageEffects.MessageEffect)?
|
||||
private var reactionContextNode: ReactionContextNode?
|
||||
|
||||
private var fromCustomEmojiContainerView: CustomEmojiContainerView?
|
||||
@ -380,7 +382,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
if let reactionItems, !reactionItems.isEmpty {
|
||||
//TODO:localize
|
||||
let reactionContextNode = ReactionContextNode(
|
||||
@ -394,24 +395,12 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
alwaysAllowPremiumReactions: false,
|
||||
allPresetReactionsAreAvailable: true,
|
||||
getEmojiContent: { animationCache, animationRenderer in
|
||||
let mappedReactionItems: [EmojiComponentReactionItem] = reactionItems.map { reaction -> EmojiComponentReactionItem in
|
||||
return EmojiComponentReactionItem(reaction: reaction.reaction.rawValue, file: reaction.stillAnimation)
|
||||
}
|
||||
|
||||
return EmojiPagerContentComponent.emojiInputData(
|
||||
return EmojiPagerContentComponent.messageEffectsInputData(
|
||||
context: context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
isStandalone: false,
|
||||
subject: .reaction(onlyTop: false),
|
||||
hasTrending: false,
|
||||
topReactionItems: mappedReactionItems,
|
||||
areUnicodeEmojiEnabled: false,
|
||||
areCustomEmojiEnabled: true,
|
||||
chatPeerId: context.account.peerId,
|
||||
selectedItems: Set(),
|
||||
hasSearch: false,
|
||||
premiumIfSavedMessages: false
|
||||
hasSearch: true,
|
||||
hideBackground: false
|
||||
)
|
||||
},
|
||||
isExpandedUpdated: { [weak self] transition in
|
||||
@ -438,73 +427,51 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
return
|
||||
}
|
||||
|
||||
let reactionItem: Signal<ReactionItem?, NoError>
|
||||
switch updateReaction.reaction {
|
||||
case .builtin:
|
||||
reactionItem = context.engine.stickers.availableReactions()
|
||||
|> take(1)
|
||||
|> map { availableReactions -> ReactionItem? in
|
||||
guard let availableReactions else {
|
||||
return nil
|
||||
}
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
if reaction.value == updateReaction.reaction {
|
||||
return ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
listAnimation: centerAnimation,
|
||||
largeListAnimation: reaction.activateAnimation,
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation,
|
||||
isCustom: false
|
||||
)
|
||||
}
|
||||
}
|
||||
guard case let .custom(sourceEffectId, _) = updateReaction else {
|
||||
return
|
||||
}
|
||||
|
||||
let messageEffect: Signal<AvailableMessageEffects.MessageEffect?, NoError>
|
||||
messageEffect = context.engine.stickers.availableMessageEffects()
|
||||
|> take(1)
|
||||
|> map { availableMessageEffects -> AvailableMessageEffects.MessageEffect? in
|
||||
guard let availableMessageEffects else {
|
||||
return nil
|
||||
}
|
||||
case .custom:
|
||||
switch updateReaction {
|
||||
case let .custom(_, file):
|
||||
if let itemFile = file {
|
||||
reactionItem = .single(ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: updateReaction.reaction),
|
||||
appearAnimation: itemFile,
|
||||
stillAnimation: itemFile,
|
||||
listAnimation: itemFile,
|
||||
largeListAnimation: itemFile,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
))
|
||||
} else {
|
||||
reactionItem = .single(nil)
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if messageEffect.id == sourceEffectId || messageEffect.effectSticker.fileId.id == sourceEffectId {
|
||||
return messageEffect
|
||||
}
|
||||
default:
|
||||
reactionItem = .single(nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
self.messageEffectDisposable.set((combineLatest(
|
||||
reactionItem,
|
||||
messageEffect,
|
||||
ReactionContextNode.randomGenericReactionEffect(context: context)
|
||||
)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] reactionItem, path in
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] messageEffect, path in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard let reactionItem else {
|
||||
guard let messageEffect else {
|
||||
return
|
||||
}
|
||||
let effectId = messageEffect.id
|
||||
|
||||
let reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: updateReaction.reaction),
|
||||
appearAnimation: messageEffect.effectSticker,
|
||||
stillAnimation: messageEffect.effectSticker,
|
||||
listAnimation: messageEffect.effectSticker,
|
||||
largeListAnimation: messageEffect.effectSticker,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
)
|
||||
|
||||
if let selectedMessageEffect = self.selectedMessageEffect {
|
||||
if selectedMessageEffect.reaction == updateReaction.reaction {
|
||||
if selectedMessageEffect.id == effectId {
|
||||
self.selectedMessageEffect = nil
|
||||
reactionContextNode.selectedItems = Set([])
|
||||
|
||||
@ -518,17 +485,17 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
self.update(transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
return
|
||||
} else {
|
||||
self.selectedMessageEffect = (reaction: updateReaction.reaction, file: reactionItem.listAnimation)
|
||||
self.selectedMessageEffect = (id: effectId, effect: messageEffect)
|
||||
reactionContextNode.selectedItems = Set([AnyHashable(updateReaction.reaction)])
|
||||
self.update(transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
} else {
|
||||
self.selectedMessageEffect = (reaction: updateReaction.reaction, file: reactionItem.listAnimation)
|
||||
self.selectedMessageEffect = (id: effectId, effect: messageEffect)
|
||||
reactionContextNode.selectedItems = Set([AnyHashable(updateReaction.reaction)])
|
||||
self.update(transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||
}
|
||||
|
||||
guard let messageEffectReactionIcon = self.messageEffectReactionIcon else {
|
||||
guard let targetView = self.messageEffectReactionIcon ?? self.messageEffectReactionText else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -546,16 +513,27 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||
self.addSubnode(standaloneReactionAnimation)
|
||||
|
||||
var customEffectResource: MediaResource?
|
||||
if let effectAnimation = messageEffect.effectAnimation {
|
||||
customEffectResource = effectAnimation.resource
|
||||
} else {
|
||||
let effectSticker = messageEffect.effectSticker
|
||||
if let effectFile = effectSticker.videoThumbnails.first {
|
||||
customEffectResource = effectFile.resource
|
||||
}
|
||||
}
|
||||
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: context,
|
||||
theme: self.presentationData.theme,
|
||||
animationCache: context.animationCache,
|
||||
reaction: reactionItem,
|
||||
customEffectResource: customEffectResource,
|
||||
avatarPeers: [],
|
||||
playHaptic: true,
|
||||
isLarge: true,
|
||||
playCenterReaction: false,
|
||||
targetView: messageEffectReactionIcon,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { standaloneReactionAnimation in
|
||||
/*guard let strongSelf = self else {
|
||||
return
|
||||
@ -899,6 +877,9 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
}
|
||||
} else {
|
||||
completedBubble = true
|
||||
if let reactionContextNode = self.reactionContextNode {
|
||||
reactionContextNode.animateOut(to: nil, animatingOutToReaction: false)
|
||||
}
|
||||
}
|
||||
|
||||
let contentOffset = CGPoint(x: self.sendButtonFrame.midX - self.contentContainerNode.frame.midX, y: self.sendButtonFrame.midY - self.contentContainerNode.frame.midY)
|
||||
@ -1048,35 +1029,89 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
|
||||
self.toMessageTextNode.updateLayout(size: textFrame.size)
|
||||
|
||||
if let selectedMessageEffect = self.selectedMessageEffect {
|
||||
let messageEffectReactionIcon: ReactionIconView
|
||||
var iconTransition = transition
|
||||
var animateIn = false
|
||||
if let current = self.messageEffectReactionIcon {
|
||||
messageEffectReactionIcon = current
|
||||
if let iconFile = selectedMessageEffect.effect.staticIcon {
|
||||
let messageEffectReactionIcon: ReactionIconView
|
||||
var iconTransition = transition
|
||||
var animateIn = false
|
||||
if let current = self.messageEffectReactionIcon {
|
||||
messageEffectReactionIcon = current
|
||||
} else {
|
||||
iconTransition = .immediate
|
||||
animateIn = true
|
||||
messageEffectReactionIcon = ReactionIconView(frame: CGRect())
|
||||
self.messageEffectReactionIcon = messageEffectReactionIcon
|
||||
self.toMessageTextScrollView.addSubview(messageEffectReactionIcon)
|
||||
}
|
||||
|
||||
let iconSize = CGSize(width: 10.0, height: 10.0)
|
||||
messageEffectReactionIcon.update(size: iconSize, context: self.context, file: iconFile, fileId: iconFile.fileId.id, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, tintColor: nil, placeholderColor: self.presentationData.theme.chat.message.stickerPlaceholderColor.withWallpaper, animateIdle: false, reaction: .custom(selectedMessageEffect.id), transition: iconTransition)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: self.toMessageTextNode.frame.minX + messageFrame.width - 30.0 + 2.0 - iconSize.width, y: self.toMessageTextNode.frame.maxY - 6.0 - iconSize.height), size: iconSize)
|
||||
iconTransition.updateFrame(view: messageEffectReactionIcon, frame: iconFrame)
|
||||
if animateIn && transition.isAnimated {
|
||||
transition.animateTransformScale(view: messageEffectReactionIcon, from: 0.001)
|
||||
messageEffectReactionIcon.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
|
||||
if let messageEffectReactionText = self.messageEffectReactionText {
|
||||
self.messageEffectReactionText = nil
|
||||
|
||||
transition.updateTransformScale(layer: messageEffectReactionText.layer, scale: 0.001)
|
||||
transition.updateAlpha(layer: messageEffectReactionText.layer, alpha: 0.0, completion: { [weak messageEffectReactionText] _ in
|
||||
messageEffectReactionText?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
iconTransition = .immediate
|
||||
animateIn = true
|
||||
messageEffectReactionIcon = ReactionIconView(frame: CGRect())
|
||||
self.messageEffectReactionIcon = messageEffectReactionIcon
|
||||
self.toMessageTextScrollView.addSubview(messageEffectReactionIcon)
|
||||
let messageEffectReactionText: ImmediateTextView
|
||||
var iconTransition = transition
|
||||
var animateIn = false
|
||||
if let current = self.messageEffectReactionText {
|
||||
messageEffectReactionText = current
|
||||
} else {
|
||||
iconTransition = .immediate
|
||||
animateIn = true
|
||||
messageEffectReactionText = ImmediateTextView()
|
||||
self.messageEffectReactionText = messageEffectReactionText
|
||||
self.toMessageTextScrollView.addSubview(messageEffectReactionText)
|
||||
}
|
||||
|
||||
let iconSize = CGSize(width: 10.0, height: 10.0)
|
||||
messageEffectReactionText.attributedText = NSAttributedString(string: selectedMessageEffect.effect.emoticon, font: Font.regular(9.0), textColor: .black)
|
||||
let textSize = messageEffectReactionText.updateLayout(CGSize(width: 100.0, height: 100.0))
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: self.toMessageTextNode.frame.minX + messageFrame.width - 30.0 + 2.0 - iconSize.width + floorToScreenPixels((iconSize.width - textSize.width) * 0.5), y: self.toMessageTextNode.frame.maxY - 6.0 - iconSize.height + floorToScreenPixels((iconSize.height - textSize.height) * 0.5)), size: textSize)
|
||||
iconTransition.updateFrame(view: messageEffectReactionText, frame: iconFrame)
|
||||
if animateIn && transition.isAnimated {
|
||||
transition.animateTransformScale(view: messageEffectReactionText, from: 0.001)
|
||||
messageEffectReactionText.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
|
||||
if let messageEffectReactionIcon = self.messageEffectReactionIcon {
|
||||
self.messageEffectReactionIcon = nil
|
||||
|
||||
transition.updateTransformScale(layer: messageEffectReactionIcon.layer, scale: 0.001)
|
||||
transition.updateAlpha(layer: messageEffectReactionIcon.layer, alpha: 0.0, completion: { [weak messageEffectReactionIcon] _ in
|
||||
messageEffectReactionIcon?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let iconSize = CGSize(width: 10.0, height: 10.0)
|
||||
messageEffectReactionIcon.update(size: iconSize, context: self.context, file: selectedMessageEffect.file, fileId: selectedMessageEffect.file.fileId.id, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, tintColor: nil, placeholderColor: self.presentationData.theme.chat.message.stickerPlaceholderColor.withWallpaper, animateIdle: false, reaction: selectedMessageEffect.reaction, transition: iconTransition)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: self.toMessageTextNode.frame.minX + messageFrame.width - 30.0 + 2.0 - iconSize.width, y: self.toMessageTextNode.frame.maxY - 6.0 - iconSize.height), size: iconSize)
|
||||
iconTransition.updateFrame(view: messageEffectReactionIcon, frame: iconFrame)
|
||||
if animateIn && transition.isAnimated {
|
||||
transition.animateTransformScale(view: messageEffectReactionIcon, from: 0.001)
|
||||
messageEffectReactionIcon.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
} else {
|
||||
if let messageEffectReactionIcon = self.messageEffectReactionIcon {
|
||||
self.messageEffectReactionIcon = nil
|
||||
|
||||
transition.updateTransformScale(layer: messageEffectReactionIcon.layer, scale: 0.001)
|
||||
transition.updateAlpha(layer: messageEffectReactionIcon.layer, alpha: 0.0, completion: { [weak messageEffectReactionIcon] _ in
|
||||
messageEffectReactionIcon?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
if let messageEffectReactionText = self.messageEffectReactionText {
|
||||
self.messageEffectReactionText = nil
|
||||
|
||||
transition.updateTransformScale(layer: messageEffectReactionText.layer, scale: 0.001)
|
||||
transition.updateAlpha(layer: messageEffectReactionText.layer, alpha: 0.0, completion: { [weak messageEffectReactionText] _ in
|
||||
messageEffectReactionText?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
} else if let messageEffectReactionIcon = self.messageEffectReactionIcon {
|
||||
self.messageEffectReactionIcon = nil
|
||||
|
||||
transition.updateTransformScale(layer: messageEffectReactionIcon.layer, scale: 0.001)
|
||||
transition.updateAlpha(layer: messageEffectReactionIcon.layer, alpha: 0.0, completion: { [weak messageEffectReactionIcon] _ in
|
||||
messageEffectReactionIcon?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
if let reactionContextNode = self.reactionContextNode {
|
||||
|
@ -0,0 +1,860 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import TextFormat
|
||||
import ReactionSelectionNode
|
||||
import ViewControllerComponent
|
||||
import ComponentFlow
|
||||
import ComponentDisplayAdapters
|
||||
import WallpaperBackgroundNode
|
||||
import ReactionSelectionNode
|
||||
import EntityKeyboard
|
||||
|
||||
func convertFrame(_ frame: CGRect, from fromView: UIView, to toView: UIView) -> CGRect {
|
||||
let sourceWindowFrame = fromView.convert(frame, to: nil)
|
||||
var targetWindowFrame = toView.convert(sourceWindowFrame, from: nil)
|
||||
|
||||
if let fromWindow = fromView.window, let toWindow = toView.window {
|
||||
targetWindowFrame.origin.x += toWindow.bounds.width - fromWindow.bounds.width
|
||||
}
|
||||
return targetWindowFrame
|
||||
}
|
||||
|
||||
final class ChatSendMessageContextScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let peerId: EnginePeer.Id?
|
||||
let isScheduledMessages: Bool
|
||||
let forwardMessageIds: [EngineMessage.Id]?
|
||||
let hasEntityKeyboard: Bool
|
||||
let gesture: ContextGesture
|
||||
let sourceSendButton: ASDisplayNode
|
||||
let textInputView: UITextView
|
||||
let emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
let wallpaperBackgroundNode: WallpaperBackgroundNode?
|
||||
let attachment: Bool
|
||||
let canSendWhenOnline: Bool
|
||||
let completion: () -> Void
|
||||
let sendMessage: (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.MessageEffect?) -> Void
|
||||
let schedule: (ChatSendMessageActionSheetController.MessageEffect?) -> Void
|
||||
let reactionItems: [ReactionItem]?
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
peerId: EnginePeer.Id?,
|
||||
isScheduledMessages: Bool,
|
||||
forwardMessageIds: [EngineMessage.Id]?,
|
||||
hasEntityKeyboard: Bool,
|
||||
gesture: ContextGesture,
|
||||
sourceSendButton: ASDisplayNode,
|
||||
textInputView: UITextView,
|
||||
emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?,
|
||||
wallpaperBackgroundNode: WallpaperBackgroundNode?,
|
||||
attachment: Bool,
|
||||
canSendWhenOnline: Bool,
|
||||
completion: @escaping () -> Void,
|
||||
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
schedule: @escaping (ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
reactionItems: [ReactionItem]?
|
||||
) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.forwardMessageIds = forwardMessageIds
|
||||
self.hasEntityKeyboard = hasEntityKeyboard
|
||||
self.gesture = gesture
|
||||
self.sourceSendButton = sourceSendButton
|
||||
self.textInputView = textInputView
|
||||
self.emojiViewProvider = emojiViewProvider
|
||||
self.wallpaperBackgroundNode = wallpaperBackgroundNode
|
||||
self.attachment = attachment
|
||||
self.canSendWhenOnline = canSendWhenOnline
|
||||
self.completion = completion
|
||||
self.sendMessage = sendMessage
|
||||
self.schedule = schedule
|
||||
self.reactionItems = reactionItems
|
||||
}
|
||||
|
||||
static func ==(lhs: ChatSendMessageContextScreenComponent, rhs: ChatSendMessageContextScreenComponent) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
enum PresentationAnimationState {
|
||||
enum Key {
|
||||
case initial
|
||||
case animatedIn
|
||||
case animatedOut
|
||||
}
|
||||
|
||||
case initial
|
||||
case animatedIn
|
||||
case animatedOut(completion: () -> Void)
|
||||
|
||||
var key: Key {
|
||||
switch self {
|
||||
case .initial:
|
||||
return .initial
|
||||
case .animatedIn:
|
||||
return .animatedIn
|
||||
case .animatedOut:
|
||||
return .animatedOut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private let backgroundView: BlurredBackgroundView
|
||||
|
||||
private var sendButton: HighlightTrackingButton?
|
||||
private var messageItemView: MessageItemView?
|
||||
private var actionsStackNode: ContextControllerActionsStackNode?
|
||||
private var reactionContextNode: ReactionContextNode?
|
||||
|
||||
private let scrollView: UIScrollView
|
||||
|
||||
private var component: ChatSendMessageContextScreenComponent?
|
||||
private var environment: EnvironmentType?
|
||||
private weak var state: EmptyComponentState?
|
||||
private var isUpdating: Bool = false
|
||||
|
||||
private let messageEffectDisposable = MetaDisposable()
|
||||
private var selectedMessageEffect: AvailableMessageEffects.MessageEffect?
|
||||
private var standaloneReactionAnimation: StandaloneReactionAnimation?
|
||||
|
||||
private var presentationAnimationState: PresentationAnimationState = .initial
|
||||
private var appliedAnimationState: PresentationAnimationState = .initial
|
||||
private var animateOutToEmpty: Bool = false
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundView = BlurredBackgroundView(color: .clear, enableBlur: true)
|
||||
|
||||
self.scrollView = UIScrollView()
|
||||
self.scrollView.showsVerticalScrollIndicator = true
|
||||
self.scrollView.showsHorizontalScrollIndicator = false
|
||||
self.scrollView.scrollsToTop = false
|
||||
self.scrollView.delaysContentTouches = false
|
||||
self.scrollView.canCancelContentTouches = true
|
||||
self.scrollView.contentInsetAdjustmentBehavior = .never
|
||||
self.scrollView.alwaysBounceVertical = true
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
|
||||
self.addSubview(self.scrollView)
|
||||
|
||||
self.backgroundView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.onBackgroundTap(_:))))
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.messageEffectDisposable.dispose()
|
||||
}
|
||||
|
||||
@objc private func onBackgroundTap(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.environment?.controller()?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func onSendButtonPressed() {
|
||||
guard let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.animateOutToEmpty = true
|
||||
component.sendMessage(.generic, self.selectedMessageEffect.flatMap({ ChatSendMessageActionSheetController.MessageEffect(id: $0.id) }))
|
||||
self.environment?.controller()?.dismiss()
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
if case .initial = self.presentationAnimationState {
|
||||
self.presentationAnimationState = .animatedIn
|
||||
self.state?.updated(transition: .spring(duration: 0.42))
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
if case .animatedOut = self.presentationAnimationState {
|
||||
} else {
|
||||
self.presentationAnimationState = .animatedOut(completion: completion)
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: ChatSendMessageContextScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
defer {
|
||||
self.isUpdating = false
|
||||
}
|
||||
|
||||
let previousAnimationState = self.appliedAnimationState
|
||||
self.appliedAnimationState = self.presentationAnimationState
|
||||
|
||||
let messageActionsSpacing: CGFloat = 7.0
|
||||
|
||||
let alphaTransition: Transition
|
||||
if transition.animation.isImmediate {
|
||||
alphaTransition = .immediate
|
||||
} else {
|
||||
alphaTransition = .easeInOut(duration: 0.25)
|
||||
}
|
||||
let _ = alphaTransition
|
||||
|
||||
let environment = environment[EnvironmentType.self].value
|
||||
|
||||
let themeUpdated = environment.theme !== self.environment?.theme
|
||||
|
||||
if self.component == nil {
|
||||
component.gesture.externalUpdated = { [weak self] view, location in
|
||||
guard let self, let actionsStackNode = self.actionsStackNode else {
|
||||
return
|
||||
}
|
||||
actionsStackNode.highlightGestureMoved(location: actionsStackNode.view.convert(location, from: view))
|
||||
}
|
||||
component.gesture.externalEnded = { [weak self] viewAndLocation in
|
||||
guard let self, let actionsStackNode = self.actionsStackNode else {
|
||||
return
|
||||
}
|
||||
if let (view, location) = viewAndLocation {
|
||||
actionsStackNode.highlightGestureMoved(location: actionsStackNode.view.convert(location, from: view))
|
||||
actionsStackNode.highlightGestureFinished(performAction: true)
|
||||
} else {
|
||||
actionsStackNode.highlightGestureFinished(performAction: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.component = component
|
||||
self.environment = environment
|
||||
self.state = state
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
|
||||
if themeUpdated {
|
||||
self.backgroundView.updateColor(
|
||||
color: environment.theme.contextMenu.dimColor,
|
||||
enableBlur: true,
|
||||
forceKeepBlur: true,
|
||||
transition: .immediate
|
||||
)
|
||||
}
|
||||
|
||||
let sendButton: HighlightTrackingButton
|
||||
if let current = self.sendButton {
|
||||
sendButton = current
|
||||
} else {
|
||||
sendButton = HighlightTrackingButton()
|
||||
sendButton.accessibilityLabel = environment.strings.MediaPicker_Send
|
||||
sendButton.addTarget(self, action: #selector(self.onSendButtonPressed), for: .touchUpInside)
|
||||
if let snapshotView = component.sourceSendButton.view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.isUserInteractionEnabled = false
|
||||
sendButton.addSubview(snapshotView)
|
||||
}
|
||||
self.sendButton = sendButton
|
||||
self.addSubview(sendButton)
|
||||
}
|
||||
|
||||
let sourceSendButtonFrame = convertFrame(component.sourceSendButton.bounds, from: component.sourceSendButton.view, to: self)
|
||||
|
||||
let sendButtonScale: CGFloat
|
||||
switch self.presentationAnimationState {
|
||||
case .initial:
|
||||
sendButtonScale = 0.75
|
||||
default:
|
||||
sendButtonScale = 1.0
|
||||
}
|
||||
|
||||
let messageItemView: MessageItemView
|
||||
if let current = self.messageItemView {
|
||||
messageItemView = current
|
||||
} else {
|
||||
messageItemView = MessageItemView(frame: CGRect())
|
||||
self.messageItemView = messageItemView
|
||||
self.addSubview(messageItemView)
|
||||
}
|
||||
|
||||
let textString: NSAttributedString
|
||||
if let attributedText = component.textInputView.attributedText {
|
||||
textString = attributedText
|
||||
} else {
|
||||
textString = NSAttributedString(string: " ", font: Font.regular(17.0), textColor: .black)
|
||||
}
|
||||
|
||||
let localSourceTextInputViewFrame = convertFrame(component.textInputView.bounds, from: component.textInputView, to: self)
|
||||
|
||||
let sourceMessageTextInsets = UIEdgeInsets(top: 7.0, left: 12.0, bottom: 6.0, right: 20.0)
|
||||
let sourceBackgroundSize = CGSize(width: localSourceTextInputViewFrame.width + 32.0, height: localSourceTextInputViewFrame.height + 4.0)
|
||||
let explicitMessageBackgroundSize: CGSize?
|
||||
switch self.presentationAnimationState {
|
||||
case .initial:
|
||||
explicitMessageBackgroundSize = sourceBackgroundSize
|
||||
case .animatedOut:
|
||||
if self.animateOutToEmpty {
|
||||
explicitMessageBackgroundSize = nil
|
||||
} else {
|
||||
explicitMessageBackgroundSize = sourceBackgroundSize
|
||||
}
|
||||
case .animatedIn:
|
||||
explicitMessageBackgroundSize = nil
|
||||
}
|
||||
|
||||
let messageTextInsets = sourceMessageTextInsets
|
||||
|
||||
let messageItemSize = messageItemView.update(
|
||||
context: component.context,
|
||||
presentationData: presentationData,
|
||||
backgroundNode: component.wallpaperBackgroundNode,
|
||||
textString: textString,
|
||||
textInsets: messageTextInsets,
|
||||
explicitBackgroundSize: explicitMessageBackgroundSize,
|
||||
maxTextWidth: localSourceTextInputViewFrame.width - 32.0,
|
||||
effect: self.presentationAnimationState.key == .animatedIn ? self.selectedMessageEffect : nil,
|
||||
transition: transition
|
||||
)
|
||||
let sourceMessageItemFrame = CGRect(origin: CGPoint(x: localSourceTextInputViewFrame.minX - sourceMessageTextInsets.left, y: localSourceTextInputViewFrame.minY - 2.0), size: messageItemSize)
|
||||
|
||||
let actionsStackNode: ContextControllerActionsStackNode
|
||||
if let current = self.actionsStackNode {
|
||||
actionsStackNode = current
|
||||
} else {
|
||||
actionsStackNode = ContextControllerActionsStackNode(
|
||||
getController: {
|
||||
return nil
|
||||
},
|
||||
requestDismiss: { _ in
|
||||
},
|
||||
requestUpdate: { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: Transition(transition))
|
||||
}
|
||||
}
|
||||
)
|
||||
actionsStackNode.layer.anchorPoint = CGPoint(x: 1.0, y: 0.0)
|
||||
|
||||
var reminders = false
|
||||
var isSecret = false
|
||||
var canSchedule = false
|
||||
if let peerId = component.peerId {
|
||||
reminders = peerId == component.context.account.peerId
|
||||
isSecret = peerId.namespace == Namespaces.Peer.SecretChat
|
||||
canSchedule = !isSecret
|
||||
}
|
||||
if component.isScheduledMessages {
|
||||
canSchedule = false
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
if !reminders {
|
||||
items.append(.action(ContextMenuActionItem(
|
||||
text: environment.strings.Conversation_SendMessage_SendSilently,
|
||||
icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, _ in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.animateOutToEmpty = true
|
||||
component.sendMessage(.silently, self.selectedMessageEffect.flatMap({ ChatSendMessageActionSheetController.MessageEffect(id: $0.id) }))
|
||||
self.environment?.controller()?.dismiss()
|
||||
}
|
||||
)))
|
||||
|
||||
if component.canSendWhenOnline && canSchedule {
|
||||
items.append(.action(ContextMenuActionItem(
|
||||
text: environment.strings.Conversation_SendMessage_SendWhenOnline,
|
||||
icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/WhenOnlineIcon"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, _ in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
self.animateOutToEmpty = true
|
||||
component.sendMessage(.whenOnline, self.selectedMessageEffect.flatMap({ ChatSendMessageActionSheetController.MessageEffect(id: $0.id) }))
|
||||
self.environment?.controller()?.dismiss()
|
||||
}
|
||||
)))
|
||||
}
|
||||
}
|
||||
if canSchedule {
|
||||
items.append(.action(ContextMenuActionItem(
|
||||
text: reminders ? environment.strings.Conversation_SendMessage_SetReminder: environment.strings.Conversation_SendMessage_ScheduleMessage,
|
||||
icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/ScheduleIcon"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, _ in
|
||||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
component.schedule(nil)
|
||||
self.environment?.controller()?.dismiss()
|
||||
}
|
||||
)))
|
||||
}
|
||||
|
||||
actionsStackNode.push(
|
||||
item: ContextControllerActionsListStackItem(
|
||||
id: nil,
|
||||
items: items,
|
||||
reactionItems: nil,
|
||||
tip: nil,
|
||||
tipSignal: .single(nil),
|
||||
dismissed: nil
|
||||
),
|
||||
currentScrollingState: nil,
|
||||
positionLock: nil,
|
||||
animated: false
|
||||
)
|
||||
self.actionsStackNode = actionsStackNode
|
||||
self.addSubview(actionsStackNode.view)
|
||||
}
|
||||
let actionsStackSize = actionsStackNode.update(
|
||||
presentationData: presentationData,
|
||||
constrainedSize: availableSize,
|
||||
presentation: .modal,
|
||||
transition: transition.containedViewLayoutTransition
|
||||
)
|
||||
let sourceActionsStackFrame = CGRect(origin: CGPoint(x: sourceSendButtonFrame.minX + 1.0 - actionsStackSize.width, y: sourceMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize)
|
||||
|
||||
if let reactionItems = component.reactionItems, !reactionItems.isEmpty {
|
||||
let reactionContextNode: ReactionContextNode
|
||||
if let current = self.reactionContextNode {
|
||||
reactionContextNode = current
|
||||
} else {
|
||||
//TODO:localize
|
||||
reactionContextNode = ReactionContextNode(
|
||||
context: component.context,
|
||||
animationCache: component.context.animationCache,
|
||||
presentationData: presentationData,
|
||||
items: reactionItems.map(ReactionContextItem.reaction),
|
||||
selectedItems: Set(),
|
||||
title: "Add an animated effect",
|
||||
reactionsLocked: false,
|
||||
alwaysAllowPremiumReactions: false,
|
||||
allPresetReactionsAreAvailable: true,
|
||||
getEmojiContent: { animationCache, animationRenderer in
|
||||
return EmojiPagerContentComponent.messageEffectsInputData(
|
||||
context: component.context,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
hasSearch: true,
|
||||
hideBackground: false
|
||||
)
|
||||
},
|
||||
isExpandedUpdated: { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: Transition(transition))
|
||||
}
|
||||
},
|
||||
requestLayout: { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: Transition(transition))
|
||||
}
|
||||
},
|
||||
requestUpdateOverlayWantsToBeBelowKeyboard: { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: Transition(transition))
|
||||
}
|
||||
}
|
||||
)
|
||||
reactionContextNode.reactionSelected = { [weak self] updateReaction, _ in
|
||||
guard let self, let component = self.component, let reactionContextNode = self.reactionContextNode else {
|
||||
return
|
||||
}
|
||||
|
||||
guard case let .custom(sourceEffectId, _) = updateReaction else {
|
||||
return
|
||||
}
|
||||
|
||||
let messageEffect: Signal<AvailableMessageEffects.MessageEffect?, NoError>
|
||||
messageEffect = component.context.engine.stickers.availableMessageEffects()
|
||||
|> take(1)
|
||||
|> map { availableMessageEffects -> AvailableMessageEffects.MessageEffect? in
|
||||
guard let availableMessageEffects else {
|
||||
return nil
|
||||
}
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if messageEffect.id == sourceEffectId || messageEffect.effectSticker.fileId.id == sourceEffectId {
|
||||
return messageEffect
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
self.messageEffectDisposable.set((combineLatest(
|
||||
messageEffect,
|
||||
ReactionContextNode.randomGenericReactionEffect(context: component.context)
|
||||
)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] messageEffect, path in
|
||||
guard let self, let component = self.component, let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
guard let messageEffect else {
|
||||
return
|
||||
}
|
||||
let effectId = messageEffect.id
|
||||
|
||||
let reactionItem = ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: updateReaction.reaction),
|
||||
appearAnimation: messageEffect.effectSticker,
|
||||
stillAnimation: messageEffect.effectSticker,
|
||||
listAnimation: messageEffect.effectSticker,
|
||||
largeListAnimation: messageEffect.effectSticker,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
)
|
||||
|
||||
if let selectedMessageEffect = self.selectedMessageEffect {
|
||||
if selectedMessageEffect.id == effectId {
|
||||
self.selectedMessageEffect = nil
|
||||
reactionContextNode.selectedItems = Set([])
|
||||
|
||||
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
||||
self.standaloneReactionAnimation = nil
|
||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
}
|
||||
return
|
||||
} else {
|
||||
self.selectedMessageEffect = messageEffect
|
||||
reactionContextNode.selectedItems = Set([AnyHashable(updateReaction.reaction)])
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.selectedMessageEffect = messageEffect
|
||||
reactionContextNode.selectedItems = Set([AnyHashable(updateReaction.reaction)])
|
||||
if !self.isUpdating {
|
||||
self.state?.updated(transition: .easeInOut(duration: 0.2))
|
||||
}
|
||||
}
|
||||
|
||||
guard let targetView = self.messageItemView?.effectIconView else {
|
||||
return
|
||||
}
|
||||
|
||||
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
||||
self.standaloneReactionAnimation = nil
|
||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
|
||||
let genericReactionEffect = path
|
||||
|
||||
let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: genericReactionEffect)
|
||||
standaloneReactionAnimation.frame = self.bounds
|
||||
self.standaloneReactionAnimation = standaloneReactionAnimation
|
||||
self.addSubnode(standaloneReactionAnimation)
|
||||
|
||||
var customEffectResource: MediaResource?
|
||||
if let effectAnimation = messageEffect.effectAnimation {
|
||||
customEffectResource = effectAnimation.resource
|
||||
} else {
|
||||
let effectSticker = messageEffect.effectSticker
|
||||
if let effectFile = effectSticker.videoThumbnails.first {
|
||||
customEffectResource = effectFile.resource
|
||||
}
|
||||
}
|
||||
|
||||
standaloneReactionAnimation.animateReactionSelection(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
animationCache: component.context.animationCache,
|
||||
reaction: reactionItem,
|
||||
customEffectResource: customEffectResource,
|
||||
avatarPeers: [],
|
||||
playHaptic: true,
|
||||
isLarge: true,
|
||||
playCenterReaction: false,
|
||||
targetView: targetView,
|
||||
addStandaloneReactionAnimation: { _ in
|
||||
},
|
||||
completion: { [weak standaloneReactionAnimation] in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
}
|
||||
)
|
||||
}))
|
||||
}
|
||||
reactionContextNode.displayTail = true
|
||||
reactionContextNode.forceTailToRight = false
|
||||
reactionContextNode.forceDark = false
|
||||
self.reactionContextNode = reactionContextNode
|
||||
self.addSubview(reactionContextNode.view)
|
||||
}
|
||||
}
|
||||
|
||||
var readySendButtonFrame = CGRect(origin: CGPoint(x: sourceSendButtonFrame.minX, y: sourceSendButtonFrame.minY), size: sourceSendButtonFrame.size)
|
||||
var readyMessageItemFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 8.0 - messageItemSize.width, y: readySendButtonFrame.maxY - 6.0 - messageItemSize.height), size: messageItemSize)
|
||||
var readyActionsStackFrame = CGRect(origin: CGPoint(x: readySendButtonFrame.minX + 1.0 - actionsStackSize.width, y: readyMessageItemFrame.maxY + messageActionsSpacing), size: actionsStackSize)
|
||||
|
||||
let bottomOverflow = readyActionsStackFrame.maxY - (availableSize.height - environment.safeInsets.bottom)
|
||||
if bottomOverflow > 0.0 {
|
||||
readyMessageItemFrame.origin.y -= bottomOverflow
|
||||
readyActionsStackFrame.origin.y -= bottomOverflow
|
||||
readySendButtonFrame.origin.y -= bottomOverflow
|
||||
}
|
||||
|
||||
let messageItemFrame: CGRect
|
||||
let actionsStackFrame: CGRect
|
||||
let sendButtonFrame: CGRect
|
||||
switch self.presentationAnimationState {
|
||||
case .initial:
|
||||
messageItemFrame = sourceMessageItemFrame
|
||||
actionsStackFrame = sourceActionsStackFrame
|
||||
sendButtonFrame = sourceSendButtonFrame
|
||||
case .animatedOut:
|
||||
if self.animateOutToEmpty {
|
||||
messageItemFrame = readyMessageItemFrame
|
||||
actionsStackFrame = readyActionsStackFrame
|
||||
sendButtonFrame = readySendButtonFrame
|
||||
} else {
|
||||
messageItemFrame = sourceMessageItemFrame
|
||||
actionsStackFrame = sourceActionsStackFrame
|
||||
sendButtonFrame = sourceSendButtonFrame
|
||||
}
|
||||
case .animatedIn:
|
||||
messageItemFrame = readyMessageItemFrame
|
||||
actionsStackFrame = readyActionsStackFrame
|
||||
sendButtonFrame = readySendButtonFrame
|
||||
}
|
||||
|
||||
transition.setFrame(view: messageItemView, frame: messageItemFrame)
|
||||
|
||||
transition.setPosition(view: actionsStackNode.view, position: CGPoint(x: actionsStackFrame.maxX, y: actionsStackFrame.minY))
|
||||
transition.setBounds(view: actionsStackNode.view, bounds: CGRect(origin: CGPoint(), size: actionsStackFrame.size))
|
||||
if !transition.animation.isImmediate && previousAnimationState.key != self.presentationAnimationState.key {
|
||||
switch self.presentationAnimationState {
|
||||
case .initial:
|
||||
break
|
||||
case .animatedIn:
|
||||
transition.setAlpha(view: actionsStackNode.view, alpha: 1.0)
|
||||
Transition.immediate.setScale(view: actionsStackNode.view, scale: 1.0)
|
||||
actionsStackNode.layer.animateSpring(from: 0.001 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.42, damping: 104.0)
|
||||
case .animatedOut:
|
||||
transition.setAlpha(view: actionsStackNode.view, alpha: 0.0)
|
||||
transition.setScale(view: actionsStackNode.view, scale: 0.001)
|
||||
}
|
||||
} else {
|
||||
switch self.presentationAnimationState {
|
||||
case .animatedIn:
|
||||
transition.setAlpha(view: actionsStackNode.view, alpha: 1.0)
|
||||
transition.setScale(view: actionsStackNode.view, scale: 1.0)
|
||||
case .animatedOut, .initial:
|
||||
transition.setAlpha(view: actionsStackNode.view, alpha: 0.0)
|
||||
transition.setScale(view: actionsStackNode.view, scale: 0.001)
|
||||
}
|
||||
}
|
||||
|
||||
if let reactionContextNode = self.reactionContextNode {
|
||||
let isFirstTime = reactionContextNode.bounds.isEmpty
|
||||
|
||||
let size = availableSize
|
||||
let reactionsAnchorRect = messageItemFrame
|
||||
transition.setFrame(view: reactionContextNode.view, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
reactionContextNode.updateLayout(size: size, insets: UIEdgeInsets(), anchorRect: reactionsAnchorRect, centerAligned: false, isCoveredByInput: false, isAnimatingOut: false, transition: transition.containedViewLayoutTransition)
|
||||
reactionContextNode.updateIsIntersectingContent(isIntersectingContent: false, transition: .immediate)
|
||||
if isFirstTime {
|
||||
reactionContextNode.animateIn(from: reactionsAnchorRect)
|
||||
} else if self.presentationAnimationState.key == .animatedOut && previousAnimationState.key == .animatedIn {
|
||||
reactionContextNode.animateOut(to: nil, animatingOutToReaction: false)
|
||||
}
|
||||
}
|
||||
if case .animatedOut = self.presentationAnimationState {
|
||||
if let standaloneReactionAnimation = self.standaloneReactionAnimation {
|
||||
self.standaloneReactionAnimation = nil
|
||||
standaloneReactionAnimation.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { [weak standaloneReactionAnimation] _ in
|
||||
standaloneReactionAnimation?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
transition.setPosition(view: sendButton, position: sendButtonFrame.center)
|
||||
transition.setBounds(view: sendButton, bounds: CGRect(origin: CGPoint(), size: sendButtonFrame.size))
|
||||
transition.setScale(view: sendButton, scale: sendButtonScale)
|
||||
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: availableSize))
|
||||
self.backgroundView.update(size: availableSize, transition: transition.containedViewLayoutTransition)
|
||||
let backgroundAlpha: CGFloat
|
||||
switch self.presentationAnimationState {
|
||||
case .animatedIn:
|
||||
component.textInputView.isHidden = true
|
||||
component.sourceSendButton.isHidden = true
|
||||
|
||||
backgroundAlpha = 1.0
|
||||
case .animatedOut:
|
||||
backgroundAlpha = 0.0
|
||||
|
||||
if self.animateOutToEmpty {
|
||||
component.textInputView.isHidden = false
|
||||
component.sourceSendButton.isHidden = false
|
||||
|
||||
transition.setAlpha(view: sendButton, alpha: 0.0)
|
||||
if let messageItemView = self.messageItemView {
|
||||
transition.setAlpha(view: messageItemView, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
default:
|
||||
backgroundAlpha = 0.0
|
||||
}
|
||||
|
||||
transition.setAlpha(view: self.backgroundView, alpha: backgroundAlpha, completion: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if case let .animatedOut(completion) = self.presentationAnimationState {
|
||||
if let component = self.component, !self.animateOutToEmpty {
|
||||
component.textInputView.isHidden = false
|
||||
component.sourceSendButton.isHidden = false
|
||||
}
|
||||
completion()
|
||||
}
|
||||
})
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View()
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: Transition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatSendMessageContextScreen: ViewControllerComponentContainer, ChatSendMessageActionSheetController {
|
||||
private let context: AccountContext
|
||||
|
||||
private var processedDidAppear: Bool = false
|
||||
private var processedDidDisappear: Bool = false
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?,
|
||||
peerId: EnginePeer.Id?,
|
||||
isScheduledMessages: Bool,
|
||||
forwardMessageIds: [EngineMessage.Id]?,
|
||||
hasEntityKeyboard: Bool,
|
||||
gesture: ContextGesture,
|
||||
sourceSendButton: ASDisplayNode,
|
||||
textInputView: UITextView,
|
||||
emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?,
|
||||
wallpaperBackgroundNode: WallpaperBackgroundNode?,
|
||||
attachment: Bool,
|
||||
canSendWhenOnline: Bool,
|
||||
completion: @escaping () -> Void,
|
||||
sendMessage: @escaping (ChatSendMessageActionSheetController.SendMode, ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
schedule: @escaping (ChatSendMessageActionSheetController.MessageEffect?) -> Void,
|
||||
reactionItems: [ReactionItem]?
|
||||
) {
|
||||
self.context = context
|
||||
|
||||
super.init(
|
||||
context: context,
|
||||
component: ChatSendMessageContextScreenComponent(
|
||||
context: context,
|
||||
peerId: peerId,
|
||||
isScheduledMessages: isScheduledMessages,
|
||||
forwardMessageIds: forwardMessageIds,
|
||||
hasEntityKeyboard: hasEntityKeyboard,
|
||||
gesture: gesture,
|
||||
sourceSendButton: sourceSendButton,
|
||||
textInputView: textInputView,
|
||||
emojiViewProvider: emojiViewProvider,
|
||||
wallpaperBackgroundNode: wallpaperBackgroundNode,
|
||||
attachment: attachment,
|
||||
canSendWhenOnline: canSendWhenOnline,
|
||||
completion: completion,
|
||||
sendMessage: sendMessage,
|
||||
schedule: schedule,
|
||||
reactionItems: reactionItems
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
statusBarStyle: .none,
|
||||
presentationMode: .default
|
||||
)
|
||||
|
||||
self.lockOrientation = true
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
|
||||
/*gesture.externalEnded = { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.dismiss()
|
||||
}*/
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if !self.processedDidAppear {
|
||||
self.processedDidAppear = true
|
||||
if let componentView = self.node.hostView.componentView as? ChatSendMessageContextScreenComponent.View {
|
||||
componentView.animateIn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func superDismiss() {
|
||||
super.dismiss()
|
||||
}
|
||||
|
||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
||||
if !self.processedDidDisappear {
|
||||
self.processedDidDisappear = true
|
||||
|
||||
if let componentView = self.node.hostView.componentView as? ChatSendMessageContextScreenComponent.View {
|
||||
componentView.animateOut(completion: { [weak self] in
|
||||
if let self {
|
||||
self.superDismiss()
|
||||
}
|
||||
completion?()
|
||||
})
|
||||
} else {
|
||||
super.dismiss(completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
318
submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift
Normal file
318
submodules/ChatSendMessageActionUI/Sources/MessageItemView.swift
Normal file
@ -0,0 +1,318 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import TelegramCore
|
||||
import TextFormat
|
||||
import ReactionSelectionNode
|
||||
import ViewControllerComponent
|
||||
import ComponentFlow
|
||||
import ComponentDisplayAdapters
|
||||
import ChatMessageBackground
|
||||
import WallpaperBackgroundNode
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import ReactionButtonListComponent
|
||||
import MultilineTextComponent
|
||||
|
||||
private final class EffectIcon: Component {
|
||||
enum Content: Equatable {
|
||||
case file(TelegramMediaFile)
|
||||
case text(String)
|
||||
}
|
||||
|
||||
let context: AccountContext
|
||||
let content: Content
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
content: Content
|
||||
) {
|
||||
self.context = context
|
||||
self.content = content
|
||||
}
|
||||
|
||||
static func ==(lhs: EffectIcon, rhs: EffectIcon) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private var fileView: ReactionIconView?
|
||||
private var textView: ComponentView<Empty>?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(component: EffectIcon, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
if case let .file(file) = component.content {
|
||||
let fileView: ReactionIconView
|
||||
if let current = self.fileView {
|
||||
fileView = current
|
||||
} else {
|
||||
fileView = ReactionIconView()
|
||||
self.fileView = fileView
|
||||
self.addSubview(fileView)
|
||||
}
|
||||
fileView.update(
|
||||
size: availableSize,
|
||||
context: component.context,
|
||||
file: file,
|
||||
fileId: file.fileId.id,
|
||||
animationCache: component.context.animationCache,
|
||||
animationRenderer: component.context.animationRenderer,
|
||||
tintColor: nil,
|
||||
placeholderColor: UIColor(white: 0.0, alpha: 0.1),
|
||||
animateIdle: false,
|
||||
reaction: .custom(file.fileId.id),
|
||||
transition: .immediate
|
||||
)
|
||||
fileView.frame = CGRect(origin: CGPoint(), size: availableSize)
|
||||
} else {
|
||||
if let fileView = self.fileView {
|
||||
self.fileView = nil
|
||||
fileView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
if case let .text(text) = component.content {
|
||||
let textView: ComponentView<Empty>
|
||||
if let current = self.textView {
|
||||
textView = current
|
||||
} else {
|
||||
textView = ComponentView()
|
||||
self.textView = textView
|
||||
}
|
||||
let textSize = textView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: text, font: Font.regular(10.0), textColor: .black))
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 100.0, height: 100.0)
|
||||
)
|
||||
let textFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - textSize.width) * 0.5), y: floorToScreenPixels((availableSize.height - textSize.height) * 0.5)), size: textSize)
|
||||
if let textComponentView = textView.view {
|
||||
if textComponentView.superview == nil {
|
||||
self.addSubview(textComponentView)
|
||||
}
|
||||
textComponentView.frame = textFrame
|
||||
}
|
||||
} else {
|
||||
if let textView = self.textView {
|
||||
self.textView = nil
|
||||
textView.view?.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
return availableSize
|
||||
}
|
||||
}
|
||||
|
||||
func makeView() -> View {
|
||||
return View(frame: CGRect())
|
||||
}
|
||||
|
||||
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
final class MessageItemView: UIView {
|
||||
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
|
||||
private let backgroundNode: ChatMessageBackground
|
||||
|
||||
private let text = ComponentView<Empty>()
|
||||
|
||||
private var effectIcon: ComponentView<Empty>?
|
||||
var effectIconView: UIView? {
|
||||
return self.effectIcon?.view
|
||||
}
|
||||
|
||||
private var chatTheme: ChatPresentationThemeData?
|
||||
private var currentSize: CGSize?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundWallpaperNode = ChatMessageBubbleBackdrop()
|
||||
self.backgroundNode = ChatMessageBackground()
|
||||
self.backgroundNode.backdropNode = self.backgroundWallpaperNode
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundWallpaperNode.view)
|
||||
self.addSubview(self.backgroundNode.view)
|
||||
}
|
||||
|
||||
required init(coder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func update(
|
||||
context: AccountContext,
|
||||
presentationData: PresentationData,
|
||||
backgroundNode: WallpaperBackgroundNode?,
|
||||
textString: NSAttributedString,
|
||||
textInsets: UIEdgeInsets,
|
||||
explicitBackgroundSize: CGSize?,
|
||||
maxTextWidth: CGFloat,
|
||||
effect: AvailableMessageEffects.MessageEffect?,
|
||||
transition: Transition
|
||||
) -> CGSize {
|
||||
var effectIconSize: CGSize?
|
||||
if let effect {
|
||||
let effectIcon: ComponentView<Empty>
|
||||
if let current = self.effectIcon {
|
||||
effectIcon = current
|
||||
} else {
|
||||
effectIcon = ComponentView()
|
||||
self.effectIcon = effectIcon
|
||||
}
|
||||
let effectIconContent: EffectIcon.Content
|
||||
if let staticIcon = effect.staticIcon {
|
||||
effectIconContent = .file(staticIcon)
|
||||
} else {
|
||||
effectIconContent = .text(effect.emoticon)
|
||||
}
|
||||
effectIconSize = effectIcon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(EffectIcon(
|
||||
context: context,
|
||||
content: effectIconContent
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 8.0, height: 8.0)
|
||||
)
|
||||
}
|
||||
|
||||
var textCutout: TextNodeCutout?
|
||||
if let effectIconSize {
|
||||
textCutout = TextNodeCutout(bottomRight: CGSize(width: effectIconSize.width + 4.0, height: effectIconSize.height))
|
||||
}
|
||||
|
||||
let textSize = self.text.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(MultilineTextWithEntitiesComponent(
|
||||
context: context,
|
||||
animationCache: context.animationCache,
|
||||
animationRenderer: context.animationRenderer,
|
||||
placeholderColor: presentationData.theme.chat.message.stickerPlaceholderColor.withWallpaper,
|
||||
text: .plain(textString),
|
||||
maximumNumberOfLines: 0,
|
||||
lineSpacing: 0.12,
|
||||
cutout: textCutout,
|
||||
insets: UIEdgeInsets()
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: maxTextWidth, height: 20000.0)
|
||||
)
|
||||
|
||||
let size = CGSize(width: textSize.width + textInsets.left + textInsets.right, height: textSize.height + textInsets.top + textInsets.bottom)
|
||||
|
||||
let textFrame = CGRect(origin: CGPoint(x: textInsets.left, y: textInsets.top), size: textSize)
|
||||
if let textView = self.text.view {
|
||||
if textView.superview == nil {
|
||||
self.addSubview(textView)
|
||||
}
|
||||
textView.frame = textFrame
|
||||
}
|
||||
|
||||
let chatTheme: ChatPresentationThemeData
|
||||
if let current = self.chatTheme, current.theme === presentationData.theme {
|
||||
chatTheme = current
|
||||
} else {
|
||||
chatTheme = ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper)
|
||||
self.chatTheme = chatTheme
|
||||
}
|
||||
|
||||
let themeGraphics = PresentationResourcesChat.principalGraphics(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||
self.backgroundWallpaperNode.setType(
|
||||
type: .outgoing(.None),
|
||||
theme: chatTheme,
|
||||
essentialGraphics: themeGraphics,
|
||||
maskMode: true,
|
||||
backgroundNode: backgroundNode
|
||||
)
|
||||
self.backgroundNode.setType(
|
||||
type: .outgoing(.None),
|
||||
highlighted: false,
|
||||
graphics: themeGraphics,
|
||||
maskMode: true,
|
||||
hasWallpaper: true,
|
||||
transition: transition.containedViewLayoutTransition,
|
||||
backgroundNode: backgroundNode
|
||||
)
|
||||
|
||||
let backgroundSize = explicitBackgroundSize ?? size
|
||||
|
||||
let previousSize = self.currentSize
|
||||
self.currentSize = backgroundSize
|
||||
|
||||
if let effectIcon = self.effectIcon, let effectIconSize {
|
||||
if let effectIconView = effectIcon.view {
|
||||
var animateIn = false
|
||||
if effectIconView.superview == nil {
|
||||
animateIn = true
|
||||
self.addSubview(effectIconView)
|
||||
}
|
||||
let effectIconFrame = CGRect(origin: CGPoint(x: backgroundSize.width - textInsets.right + 2.0 - effectIconSize.width, y: backgroundSize.height - textInsets.bottom - 2.0 - effectIconSize.height), size: effectIconSize)
|
||||
if animateIn {
|
||||
if let previousSize {
|
||||
let previousEffectIconFrame = CGRect(origin: CGPoint(x: previousSize.width - textInsets.right + 2.0 - effectIconSize.width, y: previousSize.height - textInsets.bottom - 2.0 - effectIconSize.height), size: effectIconSize)
|
||||
effectIconView.frame = previousEffectIconFrame
|
||||
} else {
|
||||
effectIconView.frame = effectIconFrame
|
||||
}
|
||||
transition.animateAlpha(view: effectIconView, from: 0.0, to: 1.0)
|
||||
if !transition.animation.isImmediate {
|
||||
effectIconView.layer.animateSpring(from: 0.001 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||
}
|
||||
}
|
||||
|
||||
transition.setFrame(view: effectIconView, frame: effectIconFrame)
|
||||
}
|
||||
} else {
|
||||
if let effectIcon = self.effectIcon {
|
||||
self.effectIcon = nil
|
||||
|
||||
if let effectIconView = effectIcon.view {
|
||||
let effectIconSize = effectIconView.bounds.size
|
||||
let effectIconFrame = CGRect(origin: CGPoint(x: backgroundSize.width - textInsets.right - effectIconSize.width, y: backgroundSize.height - textInsets.bottom - effectIconSize.height), size: effectIconSize)
|
||||
transition.setFrame(view: effectIconView, frame: effectIconFrame)
|
||||
transition.setScale(view: effectIconView, scale: 0.001)
|
||||
transition.setAlpha(view: effectIconView, alpha: 0.0, completion: { [weak effectIconView] _ in
|
||||
effectIconView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let backgroundAlpha: CGFloat
|
||||
if explicitBackgroundSize != nil {
|
||||
backgroundAlpha = 0.0
|
||||
} else {
|
||||
backgroundAlpha = 1.0
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.backgroundWallpaperNode.view, frame: CGRect(origin: CGPoint(), size: backgroundSize))
|
||||
transition.setAlpha(view: self.backgroundWallpaperNode.view, alpha: backgroundAlpha)
|
||||
self.backgroundWallpaperNode.updateFrame(CGRect(origin: CGPoint(), size: backgroundSize), transition: transition.containedViewLayoutTransition)
|
||||
transition.setFrame(view: self.backgroundNode.view, frame: CGRect(origin: CGPoint(), size: backgroundSize))
|
||||
transition.setAlpha(view: self.backgroundNode.view, alpha: backgroundAlpha)
|
||||
self.backgroundNode.updateLayout(size: backgroundSize, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
return backgroundSize
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con
|
||||
items.append(.action(ContextMenuActionItem(text: strings.StoryFeed_ContextOpenProfile, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let _ = (context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
|
||||
)
|
||||
|
@ -778,7 +778,7 @@ public class ContactsController: ViewController {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Contacts_AddContact, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -789,7 +789,7 @@ public class ContactsController: ViewController {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Contacts_AddPeopleNearby, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Contact List/Context Menu/PeopleNearby"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
@ -101,11 +101,11 @@ public struct ContextMenuActionBadge: Equatable {
|
||||
|
||||
public final class ContextMenuActionItem {
|
||||
public final class Action {
|
||||
public let controller: ContextControllerProtocol
|
||||
public let controller: ContextControllerProtocol?
|
||||
public let dismissWithResult: (ContextMenuActionResult) -> Void
|
||||
public let updateAction: (AnyHashable, ContextMenuActionItem) -> Void
|
||||
|
||||
init(controller: ContextControllerProtocol, dismissWithResult: @escaping (ContextMenuActionResult) -> Void, updateAction: @escaping (AnyHashable, ContextMenuActionItem) -> Void) {
|
||||
init(controller: ContextControllerProtocol?, dismissWithResult: @escaping (ContextMenuActionResult) -> Void, updateAction: @escaping (AnyHashable, ContextMenuActionItem) -> Void) {
|
||||
self.controller = controller
|
||||
self.dismissWithResult = dismissWithResult
|
||||
self.updateAction = updateAction
|
||||
@ -155,7 +155,7 @@ public final class ContextMenuActionItem {
|
||||
iconAnimation: IconAnimation? = nil,
|
||||
textIcon: @escaping (PresentationTheme) -> UIImage? = { _ in return nil },
|
||||
textLinkAction: @escaping () -> Void = {},
|
||||
action: ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?
|
||||
action: ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)?
|
||||
) {
|
||||
self.init(
|
||||
id: id,
|
||||
|
@ -175,12 +175,8 @@ public final class ContextControllerActionsListActionItemNode: HighlightTracking
|
||||
}
|
||||
|
||||
@objc private func pressed() {
|
||||
guard let controller = self.getController() else {
|
||||
return
|
||||
}
|
||||
|
||||
self.item.action?(ContextMenuActionItem.Action(
|
||||
controller: controller,
|
||||
controller: self.getController(),
|
||||
dismissWithResult: { [weak self] result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -669,7 +665,7 @@ private final class ContextControllerActionsListCustomItemNode: ASDisplayNode, C
|
||||
}
|
||||
}
|
||||
|
||||
final class ContextControllerActionsListStackItem: ContextControllerActionsStackItem {
|
||||
public final class ContextControllerActionsListStackItem: ContextControllerActionsStackItem {
|
||||
final class Node: ASDisplayNode, ContextControllerActionsStackItemNode {
|
||||
private final class Item {
|
||||
let node: ContextControllerActionsListItemNode
|
||||
@ -933,14 +929,14 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
|
||||
}
|
||||
}
|
||||
|
||||
let id: AnyHashable?
|
||||
let items: [ContextMenuItem]
|
||||
let reactionItems: ContextControllerReactionItems?
|
||||
let tip: ContextController.Tip?
|
||||
let tipSignal: Signal<ContextController.Tip?, NoError>?
|
||||
let dismissed: (() -> Void)?
|
||||
public let id: AnyHashable?
|
||||
public let items: [ContextMenuItem]
|
||||
public let reactionItems: ContextControllerReactionItems?
|
||||
public let tip: ContextController.Tip?
|
||||
public let tipSignal: Signal<ContextController.Tip?, NoError>?
|
||||
public let dismissed: (() -> Void)?
|
||||
|
||||
init(
|
||||
public init(
|
||||
id: AnyHashable?,
|
||||
items: [ContextMenuItem],
|
||||
reactionItems: ContextControllerReactionItems?,
|
||||
@ -956,7 +952,7 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack
|
||||
self.dismissed = dismissed
|
||||
}
|
||||
|
||||
func node(
|
||||
public func node(
|
||||
getController: @escaping () -> ContextControllerProtocol?,
|
||||
requestDismiss: @escaping (ContextMenuActionResult) -> Void,
|
||||
requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void,
|
||||
@ -1094,8 +1090,8 @@ func makeContextControllerActionsStackItem(items: ContextController.Items) -> [C
|
||||
}
|
||||
}
|
||||
|
||||
final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
enum Presentation {
|
||||
public final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
public enum Presentation {
|
||||
case modal
|
||||
case inline
|
||||
case additional
|
||||
@ -1372,19 +1368,19 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
|
||||
private var selectionPanGesture: UIPanGestureRecognizer?
|
||||
|
||||
var topReactionItems: ContextControllerReactionItems? {
|
||||
public var topReactionItems: ContextControllerReactionItems? {
|
||||
return self.itemContainers.last?.reactionItems
|
||||
}
|
||||
|
||||
var topPositionLock: CGFloat? {
|
||||
public var topPositionLock: CGFloat? {
|
||||
return self.itemContainers.last?.positionLock
|
||||
}
|
||||
|
||||
var storedScrollingState: CGFloat? {
|
||||
public var storedScrollingState: CGFloat? {
|
||||
return self.itemContainers.last?.storedScrollingState
|
||||
}
|
||||
|
||||
init(
|
||||
public init(
|
||||
getController: @escaping () -> ContextControllerProtocol?,
|
||||
requestDismiss: @escaping (ContextMenuActionResult) -> Void,
|
||||
requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void
|
||||
@ -1434,7 +1430,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func replace(item: ContextControllerActionsStackItem, animated: Bool?) {
|
||||
public func replace(item: ContextControllerActionsStackItem, animated: Bool?) {
|
||||
if let item = item as? ContextControllerActionsListStackItem, let topContainer = self.itemContainers.first, let topItem = topContainer.item as? ContextControllerActionsListStackItem, let topId = topItem.id, let id = item.id, topId == id, item.items.count == topItem.items.count {
|
||||
if let topNode = topContainer.node as? ContextControllerActionsListStackItem.Node {
|
||||
var matches = true
|
||||
@ -1491,7 +1487,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
self.push(item: item, currentScrollingState: nil, positionLock: nil, animated: resolvedAnimated)
|
||||
}
|
||||
|
||||
func push(item: ContextControllerActionsStackItem, currentScrollingState: CGFloat?, positionLock: CGFloat?, animated: Bool) {
|
||||
public func push(item: ContextControllerActionsStackItem, currentScrollingState: CGFloat?, positionLock: CGFloat?, animated: Bool) {
|
||||
if let itemContainer = self.itemContainers.last {
|
||||
itemContainer.storedScrollingState = currentScrollingState
|
||||
}
|
||||
@ -1525,11 +1521,11 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
self.requestUpdate(transition)
|
||||
}
|
||||
|
||||
func clearStoredScrollingState() {
|
||||
public func clearStoredScrollingState() {
|
||||
self.itemContainers.last?.storedScrollingState = nil
|
||||
}
|
||||
|
||||
func pop() {
|
||||
public func pop() {
|
||||
if self.itemContainers.count == 1 {
|
||||
//dismiss
|
||||
} else {
|
||||
@ -1546,7 +1542,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
self.requestUpdate(transition)
|
||||
}
|
||||
|
||||
func update(
|
||||
public func update(
|
||||
presentationData: PresentationData,
|
||||
constrainedSize: CGSize,
|
||||
presentation: Presentation,
|
||||
@ -1770,37 +1766,37 @@ final class ContextControllerActionsStackNode: ASDisplayNode {
|
||||
return CGSize(width: topItemWidth, height: topItemSize.height)
|
||||
}
|
||||
|
||||
func highlightGestureMoved(location: CGPoint) {
|
||||
public func highlightGestureMoved(location: CGPoint) {
|
||||
if let topItemContainer = self.itemContainers.last {
|
||||
topItemContainer.highlightGestureMoved(location: self.view.convert(location, to: topItemContainer.view))
|
||||
}
|
||||
}
|
||||
|
||||
func highlightGestureFinished(performAction: Bool) {
|
||||
public func highlightGestureFinished(performAction: Bool) {
|
||||
if let topItemContainer = self.itemContainers.last {
|
||||
topItemContainer.highlightGestureFinished(performAction: performAction)
|
||||
}
|
||||
}
|
||||
|
||||
func decreaseHighlightedIndex() {
|
||||
public func decreaseHighlightedIndex() {
|
||||
if let topItemContainer = self.itemContainers.last {
|
||||
topItemContainer.decreaseHighlightedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func increaseHighlightedIndex() {
|
||||
public func increaseHighlightedIndex() {
|
||||
if let topItemContainer = self.itemContainers.last {
|
||||
topItemContainer.increaseHighlightedIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func updatePanSelection(isEnabled: Bool) {
|
||||
public func updatePanSelection(isEnabled: Bool) {
|
||||
if let selectionPanGesture = self.selectionPanGesture {
|
||||
selectionPanGesture.isEnabled = isEnabled
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
public func animateIn() {
|
||||
for itemContainer in self.itemContainers {
|
||||
if let tipNode = itemContainer.tipNode {
|
||||
tipNode.animateIn()
|
||||
|
@ -2503,11 +2503,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
return optionsRateImage(rate: speedIconText, isLarge: false, color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
c.setItems(strongSelf.contextMenuSpeedItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuSpeedItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
@ -2633,10 +2633,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuMainItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuMainItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
|
||||
let sliderValuePromise = ValuePromise<Double?>(nil)
|
||||
|
@ -433,6 +433,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
private var availableReactionsDisposable: Disposable?
|
||||
|
||||
public let alwaysAllowPremiumReactions: Bool
|
||||
private var hideExpandedTopPanel: Bool = false
|
||||
private var hasPremium: Bool?
|
||||
private var hasPremiumDisposable: Disposable?
|
||||
|
||||
@ -660,6 +661,8 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.hideExpandedTopPanel = emojiContent.panelItemGroups.isEmpty
|
||||
|
||||
var emojiContent = emojiContent
|
||||
if let emojiSearchResult = emojiSearchState.result {
|
||||
var emptySearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
||||
@ -702,7 +705,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
var hideTopPanel = false
|
||||
if strongSelf.isReactionSearchActive {
|
||||
hideTopPanel = true
|
||||
} else if strongSelf.alwaysAllowPremiumReactions {
|
||||
} else if strongSelf.alwaysAllowPremiumReactions || strongSelf.hideExpandedTopPanel {
|
||||
hideTopPanel = true
|
||||
}
|
||||
|
||||
@ -717,7 +720,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
backgroundColor: .clear,
|
||||
separatorColor: strongSelf.presentationData.theme.list.itemPlainSeparatorColor.withMultipliedAlpha(0.5),
|
||||
hideTopPanel: hideTopPanel,
|
||||
disableTopPanel: strongSelf.alwaysAllowPremiumReactions,
|
||||
disableTopPanel: strongSelf.alwaysAllowPremiumReactions || strongSelf.hideExpandedTopPanel,
|
||||
hideTopPanelUpdated: { hideTopPanel, transition in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -1193,7 +1196,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}
|
||||
var baseNextFrame = CGRect(origin: CGPoint(x: self.scrollNode.view.bounds.width - expandItemSize - 9.0, y: self.contentTopInset + containerHeight - contentHeight + floor((contentHeight - expandItemSize) / 2.0)), size: CGSize(width: expandItemSize, height: expandItemSize + self.extensionDistance))
|
||||
if self.isExpanded {
|
||||
if self.alwaysAllowPremiumReactions {
|
||||
if self.alwaysAllowPremiumReactions || self.hideExpandedTopPanel {
|
||||
} else {
|
||||
baseNextFrame.origin.y += 46.0 + 54.0 - 4.0
|
||||
}
|
||||
@ -1322,7 +1325,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
var scrollFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: actualBackgroundFrame.size)
|
||||
if self.isExpanded {
|
||||
if self.alwaysAllowPremiumReactions {
|
||||
if self.alwaysAllowPremiumReactions || self.hideExpandedTopPanel {
|
||||
scrollFrame.origin.y += 0.0
|
||||
} else {
|
||||
scrollFrame.origin.y += 46.0 + 54.0 - 4.0
|
||||
@ -1347,7 +1350,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
self.updateScrolling(transition: transition)
|
||||
|
||||
self.emojiContentLayout = EmojiPagerContentComponent.CustomLayout(
|
||||
topPanelAlwaysHidden: self.alwaysAllowPremiumReactions,
|
||||
topPanelAlwaysHidden: self.alwaysAllowPremiumReactions || self.hideExpandedTopPanel,
|
||||
itemsPerRow: itemCount,
|
||||
itemSize: itemSize,
|
||||
sideInset: sideInset,
|
||||
@ -1377,7 +1380,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
var hideTopPanel = false
|
||||
if self.isReactionSearchActive {
|
||||
hideTopPanel = true
|
||||
} else if self.alwaysAllowPremiumReactions {
|
||||
} else if self.alwaysAllowPremiumReactions || self.hideExpandedTopPanel {
|
||||
hideTopPanel = true
|
||||
}
|
||||
|
||||
@ -1603,7 +1606,7 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
if !self.didInitializeEmojiContentHeight {
|
||||
self.didInitializeEmojiContentHeight = true
|
||||
|
||||
if emojiContent.contentItemGroups.count == 1 {
|
||||
if emojiContent.contentItemGroups.count == 1 && emojiContent.contentItemGroups[0].title == nil {
|
||||
let itemCount = emojiContent.contentItemGroups[0].items.count
|
||||
let numRows = (itemCount + (emojiContentLayout.itemsPerRow - 1)) / emojiContentLayout.itemsPerRow
|
||||
let proposedHeight: CGFloat = CGFloat(numRows) * emojiContentLayout.itemSize + CGFloat(numRows - 1) * emojiContentLayout.itemSpacing + emojiContentLayout.itemSpacing * 2.0 + 5.0
|
||||
@ -2972,13 +2975,13 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
self.isUserInteractionEnabled = false
|
||||
}
|
||||
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) {
|
||||
self.animateReactionSelection(context: context, theme: theme, animationCache: animationCache, reaction: reaction, avatarPeers: avatarPeers, playHaptic: playHaptic, isLarge: isLarge, playCenterReaction: playCenterReaction, forceSmallEffectAnimation: forceSmallEffectAnimation, hideCenterAnimation: hideCenterAnimation, targetView: targetView, addStandaloneReactionAnimation: addStandaloneReactionAnimation, currentItemNode: nil, completion: completion)
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, completion: @escaping () -> Void) {
|
||||
self.animateReactionSelection(context: context, theme: theme, animationCache: animationCache, reaction: reaction, customEffectResource: customEffectResource, avatarPeers: avatarPeers, playHaptic: playHaptic, isLarge: isLarge, playCenterReaction: playCenterReaction, forceSmallEffectAnimation: forceSmallEffectAnimation, hideCenterAnimation: hideCenterAnimation, targetView: targetView, addStandaloneReactionAnimation: addStandaloneReactionAnimation, currentItemNode: nil, completion: completion)
|
||||
}
|
||||
|
||||
public var currentDismissAnimation: (() -> Void)?
|
||||
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, currentItemNode: ReactionNode?, completion: @escaping () -> Void) {
|
||||
public func animateReactionSelection(context: AccountContext, theme: PresentationTheme, animationCache: AnimationCache, reaction: ReactionItem, customEffectResource: MediaResource? = nil, avatarPeers: [EnginePeer], playHaptic: Bool, isLarge: Bool, playCenterReaction: Bool = true, forceSmallEffectAnimation: Bool = false, hideCenterAnimation: Bool = false, targetView: UIView, addStandaloneReactionAnimation: ((StandaloneReactionAnimation) -> Void)?, currentItemNode: ReactionNode?, completion: @escaping () -> Void) {
|
||||
guard let sourceSnapshotView = targetView.snapshotContentTree() else {
|
||||
completion()
|
||||
return
|
||||
@ -3089,17 +3092,20 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
itemNode.updateLayout(size: expandedFrame.size, isExpanded: true, largeExpanded: isLarge, isPreviewing: false, transition: .immediate)
|
||||
}
|
||||
|
||||
let additionalAnimation: TelegramMediaFile?
|
||||
var additionalAnimationResource: MediaResource?
|
||||
if isLarge && !forceSmallEffectAnimation {
|
||||
additionalAnimation = reaction.largeApplicationAnimation
|
||||
additionalAnimationResource = reaction.largeApplicationAnimation?.resource
|
||||
} else {
|
||||
additionalAnimation = reaction.applicationAnimation
|
||||
additionalAnimationResource = reaction.applicationAnimation?.resource
|
||||
}
|
||||
if additionalAnimationResource == nil, let customEffectResource {
|
||||
additionalAnimationResource = customEffectResource
|
||||
}
|
||||
|
||||
let additionalAnimationNode: AnimatedStickerNode?
|
||||
var genericAnimationView: AnimationView?
|
||||
|
||||
if let additionalAnimation = additionalAnimation {
|
||||
if let additionalAnimationResource {
|
||||
let additionalAnimationNodeValue: AnimatedStickerNode
|
||||
if self.useDirectRendering {
|
||||
additionalAnimationNodeValue = DirectAnimatedStickerNode()
|
||||
@ -3116,7 +3122,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
||||
|
||||
let additionalCachePathPrefix: String? = nil
|
||||
|
||||
additionalAnimationNodeValue.setup(source: AnimatedStickerResourceSource(account: context.account, resource: additionalAnimation.resource), width: Int(effectFrame.width * 1.33), height: Int(effectFrame.height * 1.33), playbackMode: .once, mode: .direct(cachePathPrefix: additionalCachePathPrefix))
|
||||
additionalAnimationNodeValue.setup(source: AnimatedStickerResourceSource(account: context.account, resource: additionalAnimationResource), width: Int(effectFrame.width * 1.33), height: Int(effectFrame.height * 1.33), playbackMode: .once, mode: .direct(cachePathPrefix: additionalCachePathPrefix))
|
||||
additionalAnimationNodeValue.frame = effectFrame
|
||||
additionalAnimationNodeValue.updateLayout(size: effectFrame.size)
|
||||
self.addSubnode(additionalAnimationNodeValue)
|
||||
|
@ -220,6 +220,12 @@ public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, E>(queue: Queue? = nil, _ s1: Signal<T1, E>, _ s2: Signal<T2, E>, _ s3: Signal<T3, E>, _ s4: Signal<T4, E>, _ s5: Signal<T5, E>, _ s6: Signal<T6, E>, _ s7: Signal<T7, E>, _ s8: Signal<T8, E>, _ s9: Signal<T9, E>, _ s10: Signal<T10, E>, _ s11: Signal<T11, E>, _ s12: Signal<T12, E>, _ s13: Signal<T13, E>, _ s14: Signal<T14, E>, _ s15: Signal<T15, E>, _ s16: Signal<T16, E>, _ s17: Signal<T17, E>, _ s18: Signal<T18, E>, _ s19: Signal<T19, E>, _ s20: Signal<T20, E>, _ s21: Signal<T21, E>, _ s22: Signal<T22, E>, _ s23: Signal<T23, E>) -> Signal<(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23), E> {
|
||||
return combineLatestAny([signalOfAny(s1), signalOfAny(s2), signalOfAny(s3), signalOfAny(s4), signalOfAny(s5), signalOfAny(s6), signalOfAny(s7), signalOfAny(s8), signalOfAny(s9), signalOfAny(s10), signalOfAny(s11), signalOfAny(s12), signalOfAny(s13), signalOfAny(s14), signalOfAny(s15), signalOfAny(s16), signalOfAny(s17), signalOfAny(s18), signalOfAny(s19), signalOfAny(s20), signalOfAny(s21), signalOfAny(s22), signalOfAny(s23)], combine: { values in
|
||||
return (values[0] as! T1, values[1] as! T2, values[2] as! T3, values[3] as! T4, values[4] as! T5, values[5] as! T6, values[6] as! T7, values[7] as! T8, values[8] as! T9, values[9] as! T10, values[10] as! T11, values[11] as! T12, values[12] as! T13, values[13] as! T14, values[14] as! T15, values[15] as! T16, values[16] as! T17, values[17] as! T18, values[18] as! T19, values[19] as! T20, values[20] as! T21, values[21] as! T22, values[22] as! T23)
|
||||
}, initialValues: [:], queue: queue)
|
||||
}
|
||||
|
||||
public func combineLatest<T, E>(queue: Queue? = nil, _ signals: [Signal<T, E>]) -> Signal<[T], E> {
|
||||
if signals.count == 0 {
|
||||
return single([T](), E.self)
|
||||
|
@ -567,7 +567,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})
|
||||
})
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})))
|
||||
@ -615,14 +615,14 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})
|
||||
}))
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -633,7 +633,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})))
|
||||
if !theme.theme.isDefault {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
@ -682,7 +682,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Theme_Context_ChangeColors, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let controller = ThemeAccentColorController(context: context, mode: .colors(themeReference: reference, create: true))
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
@ -815,7 +815,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})
|
||||
})
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})))
|
||||
@ -868,14 +868,14 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})
|
||||
}))
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -886,7 +886,7 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
||||
})))
|
||||
if cloudThemeExists && !cloudTheme.theme.isDefault {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
|
@ -653,7 +653,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
})
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})))
|
||||
@ -701,14 +701,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
}))
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -718,7 +718,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
@ -766,7 +766,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Theme_Context_ChangeColors, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let controller = ThemeAccentColorController(context: context, mode: .colors(themeReference: reference, create: true))
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
@ -899,7 +899,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
})
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})))
|
||||
@ -952,14 +952,14 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})
|
||||
}))
|
||||
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pushControllerImpl?(controller)
|
||||
})
|
||||
})
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -970,7 +970,7 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
})))
|
||||
if cloudThemeExists {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
|
@ -2024,7 +2024,7 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ViewInChannel, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let peer = peer else {
|
||||
|
@ -539,7 +539,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: title, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: iconName), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let peer = peer, let navigationController = controller?.navigationController as? NavigationController else {
|
||||
|
@ -570,7 +570,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c ,f in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})),
|
||||
.separator,
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Stickers_Delete_ForEveryone, textColor: .destructive, icon: { _ in return nil }, action: { [weak self] _ ,f in
|
||||
@ -591,7 +591,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
}
|
||||
}))
|
||||
]
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(contextItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(contextItems))))
|
||||
}
|
||||
})))
|
||||
}
|
||||
@ -1162,7 +1162,7 @@ private final class StickerPackContainer: ASDisplayNode {
|
||||
self?.togglePackInstalled()
|
||||
}))
|
||||
]
|
||||
c.setItems(.single(ContextController.Items(content: .list(contextItems))), minHeight: nil, animated: true)
|
||||
c?.setItems(.single(ContextController.Items(content: .list(contextItems))), minHeight: nil, animated: true)
|
||||
} else {
|
||||
f(.default)
|
||||
self.presentDeletePack()
|
||||
|
@ -70,6 +70,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1163561432] = { return Api.AutoDownloadSettings.parse_autoDownloadSettings($0) }
|
||||
dict[-2124403385] = { return Api.AutoSaveException.parse_autoSaveException($0) }
|
||||
dict[-934791986] = { return Api.AutoSaveSettings.parse_autoSaveSettings($0) }
|
||||
dict[-1815879042] = { return Api.AvailableEffect.parse_availableEffect($0) }
|
||||
dict[-1065882623] = { return Api.AvailableReaction.parse_availableReaction($0) }
|
||||
dict[-177732982] = { return Api.BankCardOpenUrl.parse_bankCardOpenUrl($0) }
|
||||
dict[1527845466] = { return Api.BaseTheme.parse_baseThemeArctic($0) }
|
||||
@ -512,7 +513,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) }
|
||||
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }
|
||||
dict[64088654] = { return Api.MediaAreaCoordinates.parse_mediaAreaCoordinates($0) }
|
||||
dict[592953125] = { return Api.Message.parse_message($0) }
|
||||
dict[-1109353426] = { return Api.Message.parse_message($0) }
|
||||
dict[-1868117372] = { return Api.Message.parse_messageEmpty($0) }
|
||||
dict[721967202] = { return Api.Message.parse_messageService($0) }
|
||||
dict[-872240531] = { return Api.MessageAction.parse_messageActionBoostApply($0) }
|
||||
@ -928,7 +929,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-997782967] = { return Api.Update.parse_updateBotStopped($0) }
|
||||
dict[-2095595325] = { return Api.Update.parse_updateBotWebhookJSON($0) }
|
||||
dict[-1684914010] = { return Api.Update.parse_updateBotWebhookJSONQuery($0) }
|
||||
dict[1550177112] = { return Api.Update.parse_updateBroadcastRevenueTransactions($0) }
|
||||
dict[-539401739] = { return Api.Update.parse_updateBroadcastRevenueTransactions($0) }
|
||||
dict[1666927625] = { return Api.Update.parse_updateChannel($0) }
|
||||
dict[-1304443240] = { return Api.Update.parse_updateChannelAvailableMessages($0) }
|
||||
dict[-761649164] = { return Api.Update.parse_updateChannelMessageForwards($0) }
|
||||
@ -1204,6 +1205,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-843329861] = { return Api.messages.AllStickers.parse_allStickers($0) }
|
||||
dict[-395967805] = { return Api.messages.AllStickers.parse_allStickersNotModified($0) }
|
||||
dict[1338747336] = { return Api.messages.ArchivedStickers.parse_archivedStickers($0) }
|
||||
dict[-1109696146] = { return Api.messages.AvailableEffects.parse_availableEffects($0) }
|
||||
dict[-772957605] = { return Api.messages.AvailableEffects.parse_availableEffectsNotModified($0) }
|
||||
dict[1989032621] = { return Api.messages.AvailableReactions.parse_availableReactions($0) }
|
||||
dict[-1626924713] = { return Api.messages.AvailableReactions.parse_availableReactionsNotModified($0) }
|
||||
dict[-347034123] = { return Api.messages.BotApp.parse_botApp($0) }
|
||||
@ -1362,7 +1365,7 @@ public extension Api {
|
||||
return parser(reader)
|
||||
}
|
||||
else {
|
||||
telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found")
|
||||
telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -1428,6 +1431,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.AutoSaveSettings:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.AvailableEffect:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.AvailableReaction:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.BankCardOpenUrl:
|
||||
@ -2180,6 +2185,8 @@ public extension Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.ArchivedStickers:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.AvailableEffects:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.AvailableReactions:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.BotApp:
|
||||
|
@ -650,6 +650,62 @@ public extension Api {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum AvailableEffect: TypeConstructorDescription {
|
||||
case availableEffect(flags: Int32, id: Int64, emoticon: String, staticIconId: Int64?, effectStickerId: Int64, effectAnimationId: Int64?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .availableEffect(let flags, let id, let emoticon, let staticIconId, let effectStickerId, let effectAnimationId):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1815879042)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
serializeString(emoticon, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(staticIconId!, buffer: buffer, boxed: false)}
|
||||
serializeInt64(effectStickerId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeInt64(effectAnimationId!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .availableEffect(let flags, let id, let emoticon, let staticIconId, let effectStickerId, let effectAnimationId):
|
||||
return ("availableEffect", [("flags", flags as Any), ("id", id as Any), ("emoticon", emoticon as Any), ("staticIconId", staticIconId as Any), ("effectStickerId", effectStickerId as Any), ("effectAnimationId", effectAnimationId as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_availableEffect(_ reader: BufferReader) -> AvailableEffect? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Int64?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt64() }
|
||||
var _5: Int64?
|
||||
_5 = reader.readInt64()
|
||||
var _6: Int64?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {_6 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.AvailableEffect.availableEffect(flags: _1!, id: _2!, emoticon: _3!, staticIconId: _4, effectStickerId: _5!, effectAnimationId: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum AvailableReaction: TypeConstructorDescription {
|
||||
case availableReaction(flags: Int32, reaction: String, title: String, staticIcon: Api.Document, appearAnimation: Api.Document, selectAnimation: Api.Document, activateAnimation: Api.Document, effectAnimation: Api.Document, aroundAnimation: Api.Document?, centerIcon: Api.Document?)
|
||||
@ -1140,43 +1196,3 @@ public extension Api {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum BotCommand: TypeConstructorDescription {
|
||||
case botCommand(command: String, description: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botCommand(let command, let description):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1032140601)
|
||||
}
|
||||
serializeString(command, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botCommand(let command, let description):
|
||||
return ("botCommand", [("command", command as Any), ("description", description as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.BotCommand.botCommand(command: _1!, description: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -628,15 +628,15 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
indirect enum Message: TypeConstructorDescription {
|
||||
case message(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?)
|
||||
case message(flags: Int32, flags2: Int32, id: Int32, fromId: Api.Peer?, fromBoostsApplied: Int32?, peerId: Api.Peer, savedPeerId: Api.Peer?, fwdFrom: Api.MessageFwdHeader?, viaBotId: Int64?, viaBusinessBotId: Int64?, replyTo: Api.MessageReplyHeader?, date: Int32, message: String, media: Api.MessageMedia?, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, views: Int32?, forwards: Int32?, replies: Api.MessageReplies?, editDate: Int32?, postAuthor: String?, groupedId: Int64?, reactions: Api.MessageReactions?, restrictionReason: [Api.RestrictionReason]?, ttlPeriod: Int32?, quickReplyShortcutId: Int32?, effect: Int64?)
|
||||
case messageEmpty(flags: Int32, id: Int32, peerId: Api.Peer?)
|
||||
case messageService(flags: Int32, id: Int32, fromId: Api.Peer?, peerId: Api.Peer, replyTo: Api.MessageReplyHeader?, date: Int32, action: Api.MessageAction, ttlPeriod: Int32?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId):
|
||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect):
|
||||
if boxed {
|
||||
buffer.appendInt32(592953125)
|
||||
buffer.appendInt32(-1109353426)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(flags2, buffer: buffer, boxed: false)
|
||||
@ -672,6 +672,7 @@ public extension Api {
|
||||
}}
|
||||
if Int(flags) & Int(1 << 25) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 30) != 0 {serializeInt32(quickReplyShortcutId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags2) & Int(1 << 2) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .messageEmpty(let flags, let id, let peerId):
|
||||
if boxed {
|
||||
@ -699,8 +700,8 @@ public extension Api {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId):
|
||||
return ("message", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("viaBusinessBotId", viaBusinessBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any), ("quickReplyShortcutId", quickReplyShortcutId as Any)])
|
||||
case .message(let flags, let flags2, let id, let fromId, let fromBoostsApplied, let peerId, let savedPeerId, let fwdFrom, let viaBotId, let viaBusinessBotId, let replyTo, let date, let message, let media, let replyMarkup, let entities, let views, let forwards, let replies, let editDate, let postAuthor, let groupedId, let reactions, let restrictionReason, let ttlPeriod, let quickReplyShortcutId, let effect):
|
||||
return ("message", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("fromId", fromId as Any), ("fromBoostsApplied", fromBoostsApplied as Any), ("peerId", peerId as Any), ("savedPeerId", savedPeerId as Any), ("fwdFrom", fwdFrom as Any), ("viaBotId", viaBotId as Any), ("viaBusinessBotId", viaBusinessBotId as Any), ("replyTo", replyTo as Any), ("date", date as Any), ("message", message as Any), ("media", media as Any), ("replyMarkup", replyMarkup as Any), ("entities", entities as Any), ("views", views as Any), ("forwards", forwards as Any), ("replies", replies as Any), ("editDate", editDate as Any), ("postAuthor", postAuthor as Any), ("groupedId", groupedId as Any), ("reactions", reactions as Any), ("restrictionReason", restrictionReason as Any), ("ttlPeriod", ttlPeriod as Any), ("quickReplyShortcutId", quickReplyShortcutId as Any), ("effect", effect as Any)])
|
||||
case .messageEmpty(let flags, let id, let peerId):
|
||||
return ("messageEmpty", [("flags", flags as Any), ("id", id as Any), ("peerId", peerId as Any)])
|
||||
case .messageService(let flags, let id, let fromId, let peerId, let replyTo, let date, let action, let ttlPeriod):
|
||||
@ -783,6 +784,8 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 25) != 0 {_25 = reader.readInt32() }
|
||||
var _26: Int32?
|
||||
if Int(_1!) & Int(1 << 30) != 0 {_26 = reader.readInt32() }
|
||||
var _27: Int64?
|
||||
if Int(_2!) & Int(1 << 2) != 0 {_27 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -809,8 +812,9 @@ public extension Api {
|
||||
let _c24 = (Int(_1!) & Int(1 << 22) == 0) || _24 != nil
|
||||
let _c25 = (Int(_1!) & Int(1 << 25) == 0) || _25 != nil
|
||||
let _c26 = (Int(_1!) & Int(1 << 30) == 0) || _26 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 {
|
||||
return Api.Message.message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, peerId: _6!, savedPeerId: _7, fwdFrom: _8, viaBotId: _9, viaBusinessBotId: _10, replyTo: _11, date: _12!, message: _13!, media: _14, replyMarkup: _15, entities: _16, views: _17, forwards: _18, replies: _19, editDate: _20, postAuthor: _21, groupedId: _22, reactions: _23, restrictionReason: _24, ttlPeriod: _25, quickReplyShortcutId: _26)
|
||||
let _c27 = (Int(_2!) & Int(1 << 2) == 0) || _27 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 {
|
||||
return Api.Message.message(flags: _1!, flags2: _2!, id: _3!, fromId: _4, fromBoostsApplied: _5, peerId: _6!, savedPeerId: _7, fwdFrom: _8, viaBotId: _9, viaBusinessBotId: _10, replyTo: _11, date: _12!, message: _13!, media: _14, replyMarkup: _15, entities: _16, views: _17, forwards: _18, replies: _19, editDate: _20, postAuthor: _21, groupedId: _22, reactions: _23, restrictionReason: _24, ttlPeriod: _25, quickReplyShortcutId: _26, effect: _27)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -1,3 +1,43 @@
|
||||
public extension Api {
|
||||
enum BotCommand: TypeConstructorDescription {
|
||||
case botCommand(command: String, description: String)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botCommand(let command, let description):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1032140601)
|
||||
}
|
||||
serializeString(command, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botCommand(let command, let description):
|
||||
return ("botCommand", [("command", command as Any), ("description", description as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botCommand(_ reader: BufferReader) -> BotCommand? {
|
||||
var _1: String?
|
||||
_1 = parseString(reader)
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.BotCommand.botCommand(command: _1!, description: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
indirect enum BotCommandScope: TypeConstructorDescription {
|
||||
case botCommandScopeChatAdmins
|
||||
@ -1160,53 +1200,3 @@ public extension Api {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum BusinessIntro: TypeConstructorDescription {
|
||||
case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .businessIntro(let flags, let title, let description, let sticker):
|
||||
if boxed {
|
||||
buffer.appendInt32(1510606445)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(title, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .businessIntro(let flags, let title, let description, let sticker):
|
||||
return ("businessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_businessIntro(_ reader: BufferReader) -> BusinessIntro? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Api.Document?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.Document
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.BusinessIntro.businessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public extension Api {
|
||||
case updateBotStopped(userId: Int64, date: Int32, stopped: Api.Bool, qts: Int32)
|
||||
case updateBotWebhookJSON(data: Api.DataJSON)
|
||||
case updateBotWebhookJSONQuery(queryId: Int64, data: Api.DataJSON, timeout: Int32)
|
||||
case updateBroadcastRevenueTransactions(balances: Api.BroadcastRevenueBalances)
|
||||
case updateBroadcastRevenueTransactions(peer: Api.Peer, balances: Api.BroadcastRevenueBalances)
|
||||
case updateChannel(channelId: Int64)
|
||||
case updateChannelAvailableMessages(channelId: Int64, availableMinId: Int32)
|
||||
case updateChannelMessageForwards(channelId: Int64, id: Int32, forwards: Int32)
|
||||
@ -396,10 +396,11 @@ public extension Api {
|
||||
data.serialize(buffer, true)
|
||||
serializeInt32(timeout, buffer: buffer, boxed: false)
|
||||
break
|
||||
case .updateBroadcastRevenueTransactions(let balances):
|
||||
case .updateBroadcastRevenueTransactions(let peer, let balances):
|
||||
if boxed {
|
||||
buffer.appendInt32(1550177112)
|
||||
buffer.appendInt32(-539401739)
|
||||
}
|
||||
peer.serialize(buffer, true)
|
||||
balances.serialize(buffer, true)
|
||||
break
|
||||
case .updateChannel(let channelId):
|
||||
@ -1413,8 +1414,8 @@ public extension Api {
|
||||
return ("updateBotWebhookJSON", [("data", data as Any)])
|
||||
case .updateBotWebhookJSONQuery(let queryId, let data, let timeout):
|
||||
return ("updateBotWebhookJSONQuery", [("queryId", queryId as Any), ("data", data as Any), ("timeout", timeout as Any)])
|
||||
case .updateBroadcastRevenueTransactions(let balances):
|
||||
return ("updateBroadcastRevenueTransactions", [("balances", balances as Any)])
|
||||
case .updateBroadcastRevenueTransactions(let peer, let balances):
|
||||
return ("updateBroadcastRevenueTransactions", [("peer", peer as Any), ("balances", balances as Any)])
|
||||
case .updateChannel(let channelId):
|
||||
return ("updateChannel", [("channelId", channelId as Any)])
|
||||
case .updateChannelAvailableMessages(let channelId, let availableMinId):
|
||||
@ -2108,13 +2109,18 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
public static func parse_updateBroadcastRevenueTransactions(_ reader: BufferReader) -> Update? {
|
||||
var _1: Api.BroadcastRevenueBalances?
|
||||
var _1: Api.Peer?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.BroadcastRevenueBalances
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
}
|
||||
var _2: Api.BroadcastRevenueBalances?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.BroadcastRevenueBalances
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
if _c1 {
|
||||
return Api.Update.updateBroadcastRevenueTransactions(balances: _1!)
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.Update.updateBroadcastRevenueTransactions(peer: _1!, balances: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -1164,6 +1164,74 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum AvailableEffects: TypeConstructorDescription {
|
||||
case availableEffects(hash: Int32, effects: [Api.AvailableEffect], documents: [Api.Document])
|
||||
case availableEffectsNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .availableEffects(let hash, let effects, let documents):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1109696146)
|
||||
}
|
||||
serializeInt32(hash, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(effects.count))
|
||||
for item in effects {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(documents.count))
|
||||
for item in documents {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .availableEffectsNotModified:
|
||||
if boxed {
|
||||
buffer.appendInt32(-772957605)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .availableEffects(let hash, let effects, let documents):
|
||||
return ("availableEffects", [("hash", hash as Any), ("effects", effects as Any), ("documents", documents as Any)])
|
||||
case .availableEffectsNotModified:
|
||||
return ("availableEffectsNotModified", [])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_availableEffects(_ reader: BufferReader) -> AvailableEffects? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: [Api.AvailableEffect]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.AvailableEffect.self)
|
||||
}
|
||||
var _3: [Api.Document]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.messages.AvailableEffects.availableEffects(hash: _1!, effects: _2!, documents: _3!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_availableEffectsNotModified(_ reader: BufferReader) -> AvailableEffects? {
|
||||
return Api.messages.AvailableEffects.availableEffectsNotModified
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum AvailableReactions: TypeConstructorDescription {
|
||||
case availableReactions(hash: Int32, reactions: [Api.AvailableReaction])
|
||||
@ -1222,45 +1290,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum BotApp: TypeConstructorDescription {
|
||||
case botApp(flags: Int32, app: Api.BotApp)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botApp(let flags, let app):
|
||||
if boxed {
|
||||
buffer.appendInt32(-347034123)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
app.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botApp(let flags, let app):
|
||||
return ("botApp", [("flags", flags as Any), ("app", app as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botApp(_ reader: BufferReader) -> BotApp? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.BotApp?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.BotApp
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.BotApp.botApp(flags: _1!, app: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,53 @@
|
||||
public extension Api {
|
||||
enum BusinessIntro: TypeConstructorDescription {
|
||||
case businessIntro(flags: Int32, title: String, description: String, sticker: Api.Document?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .businessIntro(let flags, let title, let description, let sticker):
|
||||
if boxed {
|
||||
buffer.appendInt32(1510606445)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(title, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .businessIntro(let flags, let title, let description, let sticker):
|
||||
return ("businessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_businessIntro(_ reader: BufferReader) -> BusinessIntro? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Api.Document?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.Document
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.BusinessIntro.businessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api {
|
||||
enum BusinessLocation: TypeConstructorDescription {
|
||||
case businessLocation(flags: Int32, geoPoint: Api.GeoPoint?, address: String)
|
||||
|
@ -1,3 +1,45 @@
|
||||
public extension Api.messages {
|
||||
enum BotApp: TypeConstructorDescription {
|
||||
case botApp(flags: Int32, app: Api.BotApp)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .botApp(let flags, let app):
|
||||
if boxed {
|
||||
buffer.appendInt32(-347034123)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
app.serialize(buffer, true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .botApp(let flags, let app):
|
||||
return ("botApp", [("flags", flags as Any), ("app", app as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_botApp(_ reader: BufferReader) -> BotApp? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Api.BotApp?
|
||||
if let signature = reader.readInt32() {
|
||||
_2 = Api.parse(reader, signature: signature) as? Api.BotApp
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.BotApp.botApp(flags: _1!, app: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum BotCallbackAnswer: TypeConstructorDescription {
|
||||
case botCallbackAnswer(flags: Int32, message: String?, url: String?, cacheTime: Int32)
|
||||
@ -1432,51 +1474,3 @@ public extension Api.messages {
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
indirect enum InvitedUsers: TypeConstructorDescription {
|
||||
case invitedUsers(updates: Api.Updates, missingInvitees: [Api.MissingInvitee])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .invitedUsers(let updates, let missingInvitees):
|
||||
if boxed {
|
||||
buffer.appendInt32(2136862630)
|
||||
}
|
||||
updates.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(missingInvitees.count))
|
||||
for item in missingInvitees {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .invitedUsers(let updates, let missingInvitees):
|
||||
return ("invitedUsers", [("updates", updates as Any), ("missingInvitees", missingInvitees as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_invitedUsers(_ reader: BufferReader) -> InvitedUsers? {
|
||||
var _1: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
var _2: [Api.MissingInvitee]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MissingInvitee.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.InvitedUsers.invitedUsers(updates: _1!, missingInvitees: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,51 @@
|
||||
public extension Api.messages {
|
||||
indirect enum InvitedUsers: TypeConstructorDescription {
|
||||
case invitedUsers(updates: Api.Updates, missingInvitees: [Api.MissingInvitee])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .invitedUsers(let updates, let missingInvitees):
|
||||
if boxed {
|
||||
buffer.appendInt32(2136862630)
|
||||
}
|
||||
updates.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(missingInvitees.count))
|
||||
for item in missingInvitees {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .invitedUsers(let updates, let missingInvitees):
|
||||
return ("invitedUsers", [("updates", updates as Any), ("missingInvitees", missingInvitees as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_invitedUsers(_ reader: BufferReader) -> InvitedUsers? {
|
||||
var _1: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
_1 = Api.parse(reader, signature: signature) as? Api.Updates
|
||||
}
|
||||
var _2: [Api.MissingInvitee]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MissingInvitee.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.messages.InvitedUsers.invitedUsers(updates: _1!, missingInvitees: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
public extension Api.messages {
|
||||
enum MessageEditData: TypeConstructorDescription {
|
||||
case messageEditData(flags: Int32)
|
||||
|
@ -2061,15 +2061,15 @@ public extension Api.functions.auth {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.auth {
|
||||
static func requestFirebaseSms(flags: Int32, phoneNumber: String, phoneCodeHash: String, safetyNetToken: String?, iosPushSecret: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
static func requestFirebaseSms(flags: Int32, phoneNumber: String, phoneCodeHash: String, playIntegrityToken: String?, iosPushSecret: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1991881904)
|
||||
buffer.appendInt32(1940588736)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(phoneNumber, buffer: buffer, boxed: false)
|
||||
serializeString(phoneCodeHash, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(safetyNetToken!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(playIntegrityToken!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(iosPushSecret!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "auth.requestFirebaseSms", parameters: [("flags", String(describing: flags)), ("phoneNumber", String(describing: phoneNumber)), ("phoneCodeHash", String(describing: phoneCodeHash)), ("safetyNetToken", String(describing: safetyNetToken)), ("iosPushSecret", String(describing: iosPushSecret))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
return (FunctionDescription(name: "auth.requestFirebaseSms", parameters: [("flags", String(describing: flags)), ("phoneNumber", String(describing: phoneNumber)), ("phoneCodeHash", String(describing: phoneCodeHash)), ("playIntegrityToken", String(describing: playIntegrityToken)), ("iosPushSecret", String(describing: iosPushSecret))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -5432,6 +5432,21 @@ public extension Api.functions.messages {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getAvailableEffects(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AvailableEffects>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-559805895)
|
||||
serializeInt32(hash, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "messages.getAvailableEffects", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.AvailableEffects? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.messages.AvailableEffects?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.messages.AvailableEffects
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func getAvailableReactions(hash: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.AvailableReactions>) {
|
||||
let buffer = Buffer()
|
||||
@ -7614,9 +7629,9 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func sendMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, media: Api.InputMedia, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func sendMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, media: Api.InputMedia, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?, effect: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(2077646913)
|
||||
buffer.appendInt32(2018673486)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)}
|
||||
@ -7632,7 +7647,8 @@ public extension Api.functions.messages {
|
||||
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 17) != 0 {quickReplyShortcut!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "messages.sendMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("media", String(describing: media)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
if Int(flags) & Int(1 << 18) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.sendMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("media", String(describing: media)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut)), ("effect", String(describing: effect))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -7643,9 +7659,9 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func sendMessage(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func sendMessage(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, message: String, randomId: Int64, replyMarkup: Api.ReplyMarkup?, entities: [Api.MessageEntity]?, scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?, effect: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-537394132)
|
||||
buffer.appendInt32(-1740662971)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)}
|
||||
@ -7660,7 +7676,8 @@ public extension Api.functions.messages {
|
||||
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 17) != 0 {quickReplyShortcut!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "messages.sendMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
if Int(flags) & Int(1 << 18) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.sendMessage", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("message", String(describing: message)), ("randomId", String(describing: randomId)), ("replyMarkup", String(describing: replyMarkup)), ("entities", String(describing: entities)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut)), ("effect", String(describing: effect))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -7671,9 +7688,9 @@ public extension Api.functions.messages {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.messages {
|
||||
static func sendMultiMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, multiMedia: [Api.InputSingleMedia], scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func sendMultiMedia(flags: Int32, peer: Api.InputPeer, replyTo: Api.InputReplyTo?, multiMedia: [Api.InputSingleMedia], scheduleDate: Int32?, sendAs: Api.InputPeer?, quickReplyShortcut: Api.InputQuickReplyShortcut?, effect: Int64?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(211175177)
|
||||
buffer.appendInt32(934757205)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 0) != 0 {replyTo!.serialize(buffer, true)}
|
||||
@ -7685,7 +7702,8 @@ public extension Api.functions.messages {
|
||||
if Int(flags) & Int(1 << 10) != 0 {serializeInt32(scheduleDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 13) != 0 {sendAs!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 17) != 0 {quickReplyShortcut!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "messages.sendMultiMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("multiMedia", String(describing: multiMedia)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
if Int(flags) & Int(1 << 18) != 0 {serializeInt64(effect!, buffer: buffer, boxed: false)}
|
||||
return (FunctionDescription(name: "messages.sendMultiMedia", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("replyTo", String(describing: replyTo)), ("multiMedia", String(describing: multiMedia)), ("scheduleDate", String(describing: scheduleDate)), ("sendAs", String(describing: sendAs)), ("quickReplyShortcut", String(describing: quickReplyShortcut)), ("effect", String(describing: effect))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
|
@ -1704,7 +1704,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
@ -2517,7 +2517,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuDisplayAsItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuDisplayAsItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
items.append(.separator)
|
||||
break
|
||||
@ -2550,7 +2550,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuAudioItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuAudioItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
}
|
||||
|
||||
@ -2587,7 +2587,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuPermissionItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuPermissionItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
}
|
||||
}
|
||||
@ -2865,7 +2865,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
return .single(items)
|
||||
}
|
||||
@ -2960,7 +2960,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
return items
|
||||
}
|
||||
@ -3006,7 +3006,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
c.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
c?.setItems(strongSelf.contextMenuMainItems() |> map { ContextController.Items(content: .list($0)) }, minHeight: nil, animated: true)
|
||||
})))
|
||||
}
|
||||
return .single(items)
|
||||
|
@ -222,6 +222,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(DerivedDataMessageAttribute.self, f: { DerivedDataMessageAttribute(decoder: $0) })
|
||||
declareEncodable(TelegramApplicationIcons.self, f: { TelegramApplicationIcons(decoder: $0) })
|
||||
declareEncodable(OutgoingQuickReplyMessageAttribute.self, f: { OutgoingQuickReplyMessageAttribute(decoder: $0) })
|
||||
declareEncodable(EffectMessageAttribute.self, f: { EffectMessageAttribute(decoder: $0) })
|
||||
return
|
||||
}()
|
||||
|
||||
|
@ -126,7 +126,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
|
||||
|
||||
func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
|
||||
switch messsage {
|
||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
let chatPeerId = messagePeerId
|
||||
return chatPeerId.peerId
|
||||
case let .messageEmpty(_, _, peerId):
|
||||
@ -142,7 +142,7 @@ func apiMessagePeerId(_ messsage: Api.Message) -> PeerId? {
|
||||
|
||||
func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||
switch message {
|
||||
case let .message(_, _, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, viaBusinessBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, fromId, _, chatPeerId, savedPeerId, fwdHeader, viaBotId, viaBusinessBotId, replyTo, _, _, media, _, entities, _, _, _, _, _, _, _, _, _, _, _):
|
||||
let peerId: PeerId = chatPeerId.peerId
|
||||
|
||||
var result = [peerId]
|
||||
@ -266,7 +266,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
|
||||
|
||||
func apiMessageAssociatedMessageIds(_ message: Api.Message) -> (replyIds: ReferencedReplyMessageIds, generalIds: [MessageId])? {
|
||||
switch message {
|
||||
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, id, _, _, chatPeerId, _, _, _, _, replyTo, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let replyTo = replyTo {
|
||||
let peerId: PeerId = chatPeerId.peerId
|
||||
|
||||
@ -609,7 +609,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
|
||||
extension StoreMessage {
|
||||
convenience init?(apiMessage: Api.Message, accountPeerId: PeerId, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) {
|
||||
switch apiMessage {
|
||||
case let .message(flags, flags2, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId):
|
||||
case let .message(flags, flags2, id, fromId, boosts, chatPeerId, savedPeerId, fwdFrom, viaBotId, viaBusinessBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod, quickReplyShortcutId, messageEffectId):
|
||||
let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId
|
||||
|
||||
var namespace = namespace
|
||||
@ -887,6 +887,10 @@ extension StoreMessage {
|
||||
if let restrictionReason = restrictionReason {
|
||||
attributes.append(RestrictedContentMessageAttribute(rules: restrictionReason.map(RestrictionRule.init(apiReason:))))
|
||||
}
|
||||
|
||||
if let messageEffectId {
|
||||
attributes.append(EffectMessageAttribute(id: messageEffectId))
|
||||
}
|
||||
|
||||
var storeFlags = StoreMessageFlags()
|
||||
|
||||
|
@ -133,7 +133,7 @@ private func sendFirebaseAuthorizationCode(accountManager: AccountManager<Telegr
|
||||
//auth.requestFirebaseSms#89464b50 flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string ios_push_secret:flags.1?string = Bool;
|
||||
var flags: Int32 = 0
|
||||
flags |= 1 << 1
|
||||
return account.network.request(Api.functions.auth.requestFirebaseSms(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, safetyNetToken: nil, iosPushSecret: firebaseSecret))
|
||||
return account.network.request(Api.functions.auth.requestFirebaseSms(flags: flags, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, playIntegrityToken: nil, iosPushSecret: firebaseSecret))
|
||||
|> mapError { _ -> SendFirebaseAuthorizationCodeError in
|
||||
return .generic
|
||||
}
|
||||
|
@ -248,6 +248,8 @@ private func filterMessageAttributesForOutgoingMessage(_ attributes: [MessageAtt
|
||||
return true
|
||||
case _ as WebpagePreviewMessageAttribute:
|
||||
return true
|
||||
case _ as EffectMessageAttribute:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), info: .acknowledgement, tag: dependencyTag)
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil), info: .acknowledgement, tag: dependencyTag)
|
||||
case let .media(inputMedia, text):
|
||||
if bubbleUpEmojiOrStickersets {
|
||||
flags |= Int32(1 << 15)
|
||||
@ -432,7 +432,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil), tag: dependencyTag)
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil), tag: dependencyTag)
|
||||
|> map(NetworkRequestResult.result)
|
||||
case let .forward(sourceInfo):
|
||||
var topMsgId: Int32?
|
||||
@ -633,7 +633,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
@ -651,7 +651,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|
@ -1776,7 +1776,7 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
|
||||
updatedState.updateNewAuthorization(isUnconfirmed: isUnconfirmed, hash: hash, date: date ?? 0, device: device ?? "", location: location ?? "")
|
||||
case let .updatePeerWallpaper(_, peer, wallpaper):
|
||||
updatedState.updateWallpaper(peerId: peer.peerId, wallpaper: wallpaper.flatMap { TelegramWallpaper(apiWallpaper: $0) })
|
||||
case let .updateBroadcastRevenueTransactions(balances):
|
||||
case let .updateBroadcastRevenueTransactions(_, balances):
|
||||
updatedState.updateRevenueBalances(RevenueStats.Balances(apiRevenueBalances: balances))
|
||||
default:
|
||||
break
|
||||
|
@ -90,6 +90,7 @@ final class AccountTaskManager {
|
||||
tasks.add(managedSynchronizeEmojiKeywordsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
|
||||
tasks.add(managedApplyPendingScheduledMessagesActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
|
||||
tasks.add(managedSynchronizeAvailableReactions(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
|
||||
tasks.add(managedSynchronizeAvailableMessageEffects(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
|
||||
tasks.add(managedSynchronizeEmojiSearchCategories(postbox: self.stateManager.postbox, network: self.stateManager.network, kind: .emoji).start())
|
||||
tasks.add(managedSynchronizeEmojiSearchCategories(postbox: self.stateManager.postbox, network: self.stateManager.network, kind: .status).start())
|
||||
tasks.add(managedSynchronizeEmojiSearchCategories(postbox: self.stateManager.postbox, network: self.stateManager.network, kind: .avatar).start())
|
||||
|
@ -96,7 +96,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes
|
||||
var updatedTimestamp: Int32?
|
||||
if let apiMessage = apiMessage {
|
||||
switch apiMessage {
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
updatedTimestamp = date
|
||||
case .messageEmpty:
|
||||
break
|
||||
|
@ -0,0 +1,312 @@
|
||||
import Foundation
|
||||
import TelegramApi
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
/*
|
||||
availableEffect flags:# premium_required:flags.3?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:flags.1?long effect_animation_id:flags.2?long = AvailableEffect;
|
||||
*/
|
||||
|
||||
public final class AvailableMessageEffects: Equatable, Codable {
|
||||
public final class MessageEffect: Equatable, Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case isPremium
|
||||
case emoticon
|
||||
case staticIcon
|
||||
case effectSticker
|
||||
case effectAnimation
|
||||
}
|
||||
|
||||
public let id: Int64
|
||||
public let isPremium: Bool
|
||||
public let emoticon: String
|
||||
public let staticIcon: TelegramMediaFile?
|
||||
public let effectSticker: TelegramMediaFile
|
||||
public let effectAnimation: TelegramMediaFile?
|
||||
|
||||
public init(
|
||||
id: Int64,
|
||||
isPremium: Bool,
|
||||
emoticon: String,
|
||||
staticIcon: TelegramMediaFile?,
|
||||
effectSticker: TelegramMediaFile,
|
||||
effectAnimation: TelegramMediaFile?
|
||||
) {
|
||||
self.id = id
|
||||
self.isPremium = isPremium
|
||||
self.emoticon = emoticon
|
||||
self.staticIcon = staticIcon
|
||||
self.effectSticker = effectSticker
|
||||
self.effectAnimation = effectAnimation
|
||||
}
|
||||
|
||||
public static func ==(lhs: MessageEffect, rhs: MessageEffect) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.isPremium != rhs.isPremium {
|
||||
return false
|
||||
}
|
||||
if lhs.emoticon != rhs.emoticon {
|
||||
return false
|
||||
}
|
||||
if lhs.staticIcon != rhs.staticIcon {
|
||||
return false
|
||||
}
|
||||
if lhs.effectSticker != rhs.effectSticker {
|
||||
return false
|
||||
}
|
||||
if lhs.effectAnimation != rhs.effectAnimation {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.id = try container.decode(Int64.self, forKey: .id)
|
||||
self.isPremium = try container.decodeIfPresent(Bool.self, forKey: .isPremium) ?? false
|
||||
self.emoticon = try container.decode(String.self, forKey: .emoticon)
|
||||
|
||||
if let staticIconData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon) {
|
||||
self.staticIcon = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data)))
|
||||
} else {
|
||||
self.staticIcon = nil
|
||||
}
|
||||
|
||||
do {
|
||||
let effectStickerData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectSticker)
|
||||
self.effectSticker = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectStickerData.data)))
|
||||
}
|
||||
|
||||
if let effectAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation) {
|
||||
self.effectAnimation = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data)))
|
||||
} else {
|
||||
self.effectAnimation = nil
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.id, forKey: .id)
|
||||
try container.encode(self.emoticon, forKey: .emoticon)
|
||||
try container.encode(self.isPremium, forKey: .isPremium)
|
||||
|
||||
if let staticIcon = self.staticIcon {
|
||||
try container.encode(PostboxEncoder().encodeObjectToRawData(staticIcon), forKey: .staticIcon)
|
||||
}
|
||||
try container.encode(PostboxEncoder().encodeObjectToRawData(self.effectSticker), forKey: .effectSticker)
|
||||
if let effectAnimation = self.effectAnimation {
|
||||
try container.encode(PostboxEncoder().encodeObjectToRawData(effectAnimation), forKey: .effectAnimation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case newHash
|
||||
case messageEffects
|
||||
}
|
||||
|
||||
public let hash: Int32
|
||||
public let messageEffects: [MessageEffect]
|
||||
|
||||
public init(
|
||||
hash: Int32,
|
||||
messageEffects: [MessageEffect]
|
||||
) {
|
||||
self.hash = hash
|
||||
self.messageEffects = messageEffects
|
||||
}
|
||||
|
||||
public static func ==(lhs: AvailableMessageEffects, rhs: AvailableMessageEffects) -> Bool {
|
||||
if lhs.hash != rhs.hash {
|
||||
return false
|
||||
}
|
||||
if lhs.messageEffects != rhs.messageEffects {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.hash = try container.decodeIfPresent(Int32.self, forKey: .newHash) ?? 0
|
||||
self.messageEffects = try container.decode([MessageEffect].self, forKey: .messageEffects)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.hash, forKey: .newHash)
|
||||
try container.encode(self.messageEffects, forKey: .messageEffects)
|
||||
}
|
||||
}
|
||||
|
||||
//availableEffect flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect;
|
||||
|
||||
private extension AvailableMessageEffects.MessageEffect {
|
||||
convenience init?(apiMessageEffect: Api.AvailableEffect, files: [Int64: TelegramMediaFile]) {
|
||||
switch apiMessageEffect {
|
||||
case let .availableEffect(flags, id, emoticon, staticIconId, effectStickerId, effectAnimationId):
|
||||
guard let effectSticker = files[effectStickerId] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let isPremium = (flags & (1 << 3)) != 0
|
||||
self.init(
|
||||
id: id,
|
||||
isPremium: isPremium,
|
||||
emoticon: emoticon,
|
||||
staticIcon: staticIconId.flatMap({ files[$0] }),
|
||||
effectSticker: effectSticker,
|
||||
effectAnimation: effectAnimationId.flatMap({ files[$0] })
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_cachedAvailableMessageEffects(postbox: Postbox) -> Signal<AvailableMessageEffects?, NoError> {
|
||||
return postbox.transaction { transaction -> AvailableMessageEffects? in
|
||||
return _internal_cachedAvailableMessageEffects(transaction: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_cachedAvailableMessageEffects(transaction: Transaction) -> AvailableMessageEffects? {
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: 0)
|
||||
|
||||
let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.availableMessageEffects, key: key))?.get(AvailableMessageEffects.self)
|
||||
if let cached = cached {
|
||||
return cached
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_setCachedAvailableMessageEffects(transaction: Transaction, availableMessageEffects: AvailableMessageEffects) {
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: 0)
|
||||
|
||||
if let entry = CodableEntry(availableMessageEffects) {
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.availableMessageEffects, key: key), entry: entry)
|
||||
}
|
||||
}
|
||||
|
||||
func managedSynchronizeAvailableMessageEffects(postbox: Postbox, network: Network) -> Signal<Never, NoError> {
|
||||
let poll = Signal<Never, NoError> { subscriber in
|
||||
let signal: Signal<Never, NoError> = _internal_cachedAvailableMessageEffects(postbox: postbox)
|
||||
|> mapToSignal { current in
|
||||
let sourceHash: Int32
|
||||
#if DEBUG
|
||||
sourceHash = 0
|
||||
#else
|
||||
sourceHash = current?.hash ?? 0
|
||||
#endif
|
||||
return (network.request(Api.functions.messages.getAvailableEffects(hash: sourceHash))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.messages.AvailableEffects?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return postbox.transaction { transaction -> Signal<Never, NoError> in
|
||||
guard let result = result else {
|
||||
return .complete()
|
||||
}
|
||||
switch result {
|
||||
case let .availableEffects(hash, effects, documents):
|
||||
var files: [Int64: TelegramMediaFile] = [:]
|
||||
for document in documents {
|
||||
if let file = telegramMediaFileFromApiDocument(document) {
|
||||
files[file.fileId.id] = file
|
||||
}
|
||||
}
|
||||
|
||||
var parsedEffects: [AvailableMessageEffects.MessageEffect] = []
|
||||
for effect in effects {
|
||||
if let parsedEffect = AvailableMessageEffects.MessageEffect(apiMessageEffect: effect, files: files) {
|
||||
parsedEffects.append(parsedEffect)
|
||||
}
|
||||
}
|
||||
_internal_setCachedAvailableMessageEffects(transaction: transaction, availableMessageEffects: AvailableMessageEffects(
|
||||
hash: hash,
|
||||
messageEffects: parsedEffects
|
||||
))
|
||||
case .availableEffectsNotModified:
|
||||
break
|
||||
}
|
||||
|
||||
var signals: [Signal<Never, NoError>] = []
|
||||
|
||||
if let availableMessageEffects = _internal_cachedAvailableMessageEffects(transaction: transaction) {
|
||||
var resources: [MediaResource] = []
|
||||
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if let staticIcon = messageEffect.staticIcon {
|
||||
resources.append(staticIcon.resource)
|
||||
}
|
||||
if messageEffect.effectSticker.isPremiumSticker {
|
||||
if let effectFile = messageEffect.effectSticker.videoThumbnails.first {
|
||||
resources.append(effectFile.resource)
|
||||
}
|
||||
} else {
|
||||
if let effectAnimation = messageEffect.effectAnimation {
|
||||
resources.append(effectAnimation.resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for resource in resources {
|
||||
signals.append(
|
||||
fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: .other, userContentType: .other, reference: .standalone(resource: resource))
|
||||
|> ignoreValues
|
||||
|> `catch` { _ -> Signal<Never, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(signals)
|
||||
|> ignoreValues
|
||||
}
|
||||
|> switchToLatest
|
||||
})
|
||||
}
|
||||
|
||||
return signal.start(completed: {
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
poll
|
||||
|> then(
|
||||
.complete()
|
||||
|> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue())
|
||||
)
|
||||
)
|
||||
|> restart
|
||||
}
|
||||
|
||||
public extension Message {
|
||||
func messageEffect(availableMessageEffects: AvailableMessageEffects?) -> AvailableMessageEffects.MessageEffect? {
|
||||
guard let availableMessageEffects else {
|
||||
return nil
|
||||
}
|
||||
for attribute in self.attributes {
|
||||
if let attribute = attribute as? EffectMessageAttribute {
|
||||
for effect in availableMessageEffects.messageEffects {
|
||||
if effect.id == attribute.id {
|
||||
return effect
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
@ -794,6 +794,7 @@ public final class PendingMessageManager {
|
||||
var scheduleTime: Int32?
|
||||
var sendAsPeerId: PeerId?
|
||||
var quickReply: OutgoingQuickReplyMessageAttribute?
|
||||
var messageEffect: EffectMessageAttribute?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
@ -824,6 +825,8 @@ public final class PendingMessageManager {
|
||||
sendAsPeerId = attribute.peerId
|
||||
} else if let attribute = attribute as? OutgoingQuickReplyMessageAttribute {
|
||||
quickReply = attribute
|
||||
} else if let attribute = attribute as? EffectMessageAttribute {
|
||||
messageEffect = attribute
|
||||
}
|
||||
}
|
||||
|
||||
@ -1016,7 +1019,13 @@ public final class PendingMessageManager {
|
||||
flags |= 1 << 17
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMultiMedia(flags: flags, peer: inputPeer, replyTo: replyTo, multiMedia: singleMedias, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut))
|
||||
var messageEffectId: Int64?
|
||||
if let messageEffect {
|
||||
flags |= 1 << 18
|
||||
messageEffectId = messageEffect.id
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMultiMedia(flags: flags, peer: inputPeer, replyTo: replyTo, multiMedia: singleMedias, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, effect: messageEffectId))
|
||||
}
|
||||
|
||||
return sendMessageRequest
|
||||
@ -1192,6 +1201,7 @@ public final class PendingMessageManager {
|
||||
var sendAsPeerId: PeerId?
|
||||
var bubbleUpEmojiOrStickersets = false
|
||||
var quickReply: OutgoingQuickReplyMessageAttribute?
|
||||
var messageEffect: EffectMessageAttribute?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
@ -1228,6 +1238,8 @@ public final class PendingMessageManager {
|
||||
sendAsPeerId = attribute.peerId
|
||||
} else if let attribute = attribute as? OutgoingQuickReplyMessageAttribute {
|
||||
quickReply = attribute
|
||||
} else if let attribute = attribute as? EffectMessageAttribute {
|
||||
messageEffect = attribute
|
||||
}
|
||||
}
|
||||
|
||||
@ -1327,7 +1339,13 @@ public final class PendingMessageManager {
|
||||
flags |= 1 << 17
|
||||
}
|
||||
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut), info: .acknowledgement, tag: dependencyTag)
|
||||
var messageEffectId: Int64?
|
||||
if let messageEffect {
|
||||
flags |= 1 << 18
|
||||
messageEffectId = messageEffect.id
|
||||
}
|
||||
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: message.text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, effect: messageEffectId), info: .acknowledgement, tag: dependencyTag)
|
||||
case let .media(inputMedia, text):
|
||||
if bubbleUpEmojiOrStickersets {
|
||||
flags |= Int32(1 << 15)
|
||||
@ -1401,8 +1419,14 @@ public final class PendingMessageManager {
|
||||
}
|
||||
flags |= 1 << 17
|
||||
}
|
||||
|
||||
var messageEffectId: Int64?
|
||||
if let messageEffect {
|
||||
flags |= 1 << 18
|
||||
messageEffectId = messageEffect.id
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut), tag: dependencyTag)
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, effect: messageEffectId), tag: dependencyTag)
|
||||
|> map(NetworkRequestResult.result)
|
||||
case let .forward(sourceInfo):
|
||||
var topMsgId: Int32?
|
||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 179
|
||||
return 180
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -58,7 +58,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
||||
self.putNext(groups)
|
||||
}
|
||||
case let .updateShortChatMessage(flags, id, fromId, chatId, message, pts, ptsCount, date, fwdFrom, viaBotId, replyHeader, entities, ttlPeriod):
|
||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil)
|
||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: .peerUser(userId: fromId), fromBoostsApplied: nil, peerId: Api.Peer.peerChat(chatId: chatId), savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil)
|
||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||
if groups.count != 0 {
|
||||
@ -74,7 +74,7 @@ class UpdateMessageService: NSObject, MTMessageService {
|
||||
|
||||
let generatedPeerId = Api.Peer.peerUser(userId: userId)
|
||||
|
||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil)
|
||||
let generatedMessage = Api.Message.message(flags: flags, flags2: 0, id: id, fromId: generatedFromId, fromBoostsApplied: nil, peerId: generatedPeerId, savedPeerId: nil, fwdFrom: fwdFrom, viaBotId: viaBotId, viaBusinessBotId: nil, replyTo: replyHeader, date: date, message: message, media: Api.MessageMedia.messageMediaEmpty, replyMarkup: nil, entities: entities, views: nil, forwards: nil, replies: nil, editDate: nil, postAuthor: nil, groupedId: nil, reactions: nil, restrictionReason: nil, ttlPeriod: ttlPeriod, quickReplyShortcutId: nil, effect: nil)
|
||||
let update = Api.Update.updateNewMessage(message: generatedMessage, pts: pts, ptsCount: ptsCount)
|
||||
let groups = groupUpdates([update], users: [], chats: [], date: date, seqRange: nil)
|
||||
if groups.count != 0 {
|
||||
|
@ -104,7 +104,7 @@ extension Api.MessageMedia {
|
||||
extension Api.Message {
|
||||
var rawId: Int32 {
|
||||
switch self {
|
||||
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, id, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return id
|
||||
case let .messageEmpty(_, id, _):
|
||||
return id
|
||||
@ -115,7 +115,7 @@ extension Api.Message {
|
||||
|
||||
func id(namespace: MessageId.Namespace = Namespaces.Message.Cloud) -> MessageId? {
|
||||
switch self {
|
||||
case let .message(_, _, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, id, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
let peerId: PeerId = messagePeerId.peerId
|
||||
return MessageId(peerId: peerId, namespace: namespace, id: id)
|
||||
case let .messageEmpty(_, id, peerId):
|
||||
@ -132,7 +132,7 @@ extension Api.Message {
|
||||
|
||||
var peerId: PeerId? {
|
||||
switch self {
|
||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
let peerId: PeerId = messagePeerId.peerId
|
||||
return peerId
|
||||
case let .messageEmpty(_, _, peerId):
|
||||
@ -145,7 +145,7 @@ extension Api.Message {
|
||||
|
||||
var timestamp: Int32? {
|
||||
switch self {
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, date, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return date
|
||||
case let .messageService(_, _, _, _, _, date, _, _):
|
||||
return date
|
||||
@ -156,7 +156,7 @@ extension Api.Message {
|
||||
|
||||
var preCachedResources: [(MediaResource, Data)]? {
|
||||
switch self {
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return media?.preCachedResources
|
||||
default:
|
||||
return nil
|
||||
@ -165,7 +165,7 @@ extension Api.Message {
|
||||
|
||||
var preCachedStories: [StoryId: Api.StoryItem]? {
|
||||
switch self {
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .message(_, _, _, _, _, _, _, _, _, _, _, _, _, media, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return media?.preCachedStories
|
||||
default:
|
||||
return nil
|
||||
|
@ -0,0 +1,18 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public class EffectMessageAttribute: MessageAttribute {
|
||||
public let id: Int64
|
||||
|
||||
public init(id: Int64) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
required public init(decoder: PostboxDecoder) {
|
||||
self.id = decoder.decodeInt64ForKey("id", orElse: 0)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt64(self.id, forKey: "id")
|
||||
}
|
||||
}
|
@ -125,6 +125,7 @@ public struct Namespaces {
|
||||
public static let peerColorOptions: Int8 = 34
|
||||
public static let savedMessageTags: Int8 = 35
|
||||
public static let applicationIcons: Int8 = 36
|
||||
public static let availableMessageEffects: Int8 = 37
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
@ -145,6 +145,10 @@ public extension TelegramEngine {
|
||||
return _internal_cachedAvailableReactions(postbox: self.account.postbox)
|
||||
}
|
||||
|
||||
public func availableMessageEffects() -> Signal<AvailableMessageEffects?, NoError> {
|
||||
return _internal_cachedAvailableMessageEffects(postbox: self.account.postbox)
|
||||
}
|
||||
|
||||
public func savedMessageTagData() -> Signal<SavedMessageTags?, NoError> {
|
||||
return self.account.postbox.combinedView(keys: [PostboxViewKey.cachedItem(_internal_savedMessageTagsCacheKey())])
|
||||
|> mapToSignal { views -> Signal<SavedMessageTags?, NoError> in
|
||||
|
@ -1045,6 +1045,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.message.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.message.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
|
@ -724,6 +724,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: message.areReactionsTags(accountPeerId: context.account.peerId),
|
||||
messageEffect: message.messageEffect(availableMessageEffects: associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: message.tags.contains(.pinned) && !associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: message.isSelfExpiring,
|
||||
@ -1711,6 +1712,24 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func messageEffectTargetView() -> UIView? {
|
||||
if let statusNode = self.statusNode, !statusNode.isHidden {
|
||||
if let result = statusNode.messageEffectTargetView() {
|
||||
return result
|
||||
}
|
||||
}
|
||||
if let result = self.contentFile?.dateAndStatusNode.messageEffectTargetView() {
|
||||
return result
|
||||
}
|
||||
if let result = self.contentMedia?.dateAndStatusNode.messageEffectTargetView() {
|
||||
return result
|
||||
}
|
||||
if let result = self.contentInstantVideo?.dateAndStatusNode.messageEffectTargetView() {
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
|
||||
return self.contentMedia?.playMediaWithSound()
|
||||
}
|
||||
|
@ -295,6 +295,10 @@ open class ChatMessageBubbleContentNode: ASDisplayNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func messageEffectTargetView() -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func targetForStoryTransition(id: StoryId) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageJoinedChannelBubbleContentNode",
|
||||
"//submodules/UIKitRuntimeUtils",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageTransitionNode",
|
||||
"//submodules/AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -71,6 +71,9 @@ import ChatMessageGiftBubbleContentNode
|
||||
import ChatMessageGiveawayBubbleContentNode
|
||||
import ChatMessageJoinedChannelBubbleContentNode
|
||||
import UIKitRuntimeUtils
|
||||
import ChatMessageTransitionNode
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
|
||||
private struct BubbleItemAttributes {
|
||||
var isAttachment: Bool
|
||||
@ -601,6 +604,9 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
private var appliedForwardInfo: (Peer?, String?)?
|
||||
private var disablesComments = true
|
||||
|
||||
private var wasPending: Bool = false
|
||||
private var didChangeFromPendingToSent: Bool = false
|
||||
|
||||
private var authorNameColor: UIColor?
|
||||
|
||||
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
|
||||
@ -641,6 +647,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
containerSize: credibilityIconView.bounds.size
|
||||
)
|
||||
}
|
||||
|
||||
self.updateVisibility()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1152,9 +1160,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
return .waitForSingleTap
|
||||
}
|
||||
}
|
||||
|
||||
if !strongSelf.backgroundNode.frame.contains(point) {
|
||||
return .waitForDoubleTap
|
||||
}
|
||||
|
||||
if strongSelf.currentMessageEffect() != nil {
|
||||
return .waitForDoubleTap
|
||||
}
|
||||
}
|
||||
|
||||
return .waitForDoubleTap
|
||||
@ -2161,6 +2174,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.message.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.message.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: message.isSelfExpiring,
|
||||
@ -2998,6 +3012,13 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
return
|
||||
}
|
||||
|
||||
if item.message.id.namespace == Namespaces.Message.Local || item.message.id.namespace == Namespaces.Message.ScheduledLocal || item.message.id.namespace == Namespaces.Message.QuickReplyLocal {
|
||||
strongSelf.wasPending = true
|
||||
}
|
||||
if strongSelf.wasPending && (item.message.id.namespace != Namespaces.Message.Local && item.message.id.namespace != Namespaces.Message.ScheduledLocal && item.message.id.namespace != Namespaces.Message.QuickReplyLocal) {
|
||||
strongSelf.didChangeFromPendingToSent = true
|
||||
}
|
||||
|
||||
let themeUpdated = strongSelf.appliedItem?.presentationData.theme.theme !== item.presentationData.theme.theme
|
||||
let previousContextFrame = strongSelf.mainContainerNode.frame
|
||||
strongSelf.mainContainerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
@ -4216,6 +4237,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
|
||||
strongSelf.updateSearchTextHighlightState()
|
||||
|
||||
strongSelf.updateVisibility()
|
||||
|
||||
if let (_, f) = strongSelf.awaitingAppliedReaction {
|
||||
strongSelf.awaitingAppliedReaction = nil
|
||||
|
||||
@ -4652,6 +4675,16 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.currentMessageEffect() != nil {
|
||||
if self.backgroundNode.frame.contains(location) {
|
||||
return .action(InternalBubbleTapAction.Action({ [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.playMessageEffect(force: true)
|
||||
}, contextMenuOnLongPress: true))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case .longTap, .doubleTap, .secondaryTap:
|
||||
if let item = self.item, self.backgroundNode.frame.contains(location) {
|
||||
@ -5541,6 +5574,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
for contentNode in self.contentNodes {
|
||||
contentNode.unreadMessageRangeUpdated()
|
||||
}
|
||||
|
||||
self.updateVisibility()
|
||||
}
|
||||
|
||||
public func animateQuizInvalidOptionSelected() {
|
||||
@ -5726,4 +5761,178 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private var forceStopAnimations: Bool = false
|
||||
private var playedPremiumStickerAnimation: Bool = false
|
||||
private var additionalAnimationNodes: [ChatMessageTransitionNode.DecorationItemNode] = []
|
||||
|
||||
private func playPremiumStickerAnimation(effect: AvailableMessageEffects.MessageEffect, force: Bool) {
|
||||
if self.playedPremiumStickerAnimation && !force {
|
||||
return
|
||||
}
|
||||
self.playedPremiumStickerAnimation = true
|
||||
|
||||
if let effectAnimation = effect.effectAnimation {
|
||||
self.playEffectAnimation(resource: effectAnimation.resource, isStickerEffect: true)
|
||||
} else {
|
||||
let effectSticker = effect.effectSticker
|
||||
if let effectFile = effectSticker.videoThumbnails.first {
|
||||
self.playEffectAnimation(resource: effectFile.resource, isStickerEffect: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func playEffectAnimation(resource: MediaResource, isStickerEffect: Bool = false) {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
}
|
||||
guard let transitionNode = item.controllerInteraction.getMessageTransitionNode() as? ChatMessageTransitionNode else {
|
||||
return
|
||||
}
|
||||
|
||||
let source = AnimatedStickerResourceSource(account: item.context.account, resource: resource, fitzModifier: nil)
|
||||
|
||||
let animationSize = CGSize(width: 180.0, height: 180.0)
|
||||
let animationNodeFrame: CGRect
|
||||
|
||||
var messageEffectView: UIView?
|
||||
for contentNode in self.contentNodes {
|
||||
if let result = contentNode.messageEffectTargetView() {
|
||||
messageEffectView = result
|
||||
break
|
||||
}
|
||||
}
|
||||
if messageEffectView == nil {
|
||||
if let mosaicStatusNode = self.mosaicStatusNode, let result = mosaicStatusNode.messageEffectTargetView() {
|
||||
messageEffectView = result
|
||||
}
|
||||
}
|
||||
|
||||
if let messageEffectView {
|
||||
animationNodeFrame = animationSize.centered(around: messageEffectView.convert(messageEffectView.bounds, to: self.view).center)
|
||||
} else {
|
||||
animationNodeFrame = animationSize.centered(around: self.backgroundNode.frame.center)
|
||||
}
|
||||
|
||||
if self.additionalAnimationNodes.count >= 4 {
|
||||
return
|
||||
}
|
||||
|
||||
let incomingMessage = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
|
||||
do {
|
||||
let pathPrefix = item.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(resource.id)
|
||||
let additionalAnimationNode = DefaultAnimatedStickerNodeImpl()
|
||||
additionalAnimationNode.setup(source: source, width: Int(animationSize.width * 1.6), height: Int(animationSize.height * 1.6), playbackMode: .once, mode: .direct(cachePathPrefix: pathPrefix))
|
||||
var animationFrame: CGRect
|
||||
if isStickerEffect {
|
||||
let scale: CGFloat = 0.245
|
||||
let offsetScale: CGFloat = 0.5
|
||||
animationFrame = animationNodeFrame.offsetBy(dx: incomingMessage ? animationNodeFrame.width * offsetScale : -animationNodeFrame.width * offsetScale, dy: -25.0).insetBy(dx: -animationNodeFrame.width * scale, dy: -animationNodeFrame.height * scale)
|
||||
} else {
|
||||
animationFrame = animationNodeFrame.insetBy(dx: -animationNodeFrame.width, dy: -animationNodeFrame.height)
|
||||
.offsetBy(dx: incomingMessage ? animationNodeFrame.width - 10.0 : -animationNodeFrame.width + 10.0, dy: 0.0)
|
||||
animationFrame = animationFrame.offsetBy(dx: CGFloat.random(in: -30.0 ... 30.0), dy: CGFloat.random(in: -30.0 ... 30.0))
|
||||
}
|
||||
|
||||
animationFrame = animationFrame.offsetBy(dx: 0.0, dy: self.insets.top)
|
||||
additionalAnimationNode.frame = animationFrame
|
||||
if incomingMessage {
|
||||
additionalAnimationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
|
||||
}
|
||||
|
||||
let decorationNode = transitionNode.add(decorationView: additionalAnimationNode.view, itemNode: self)
|
||||
additionalAnimationNode.completed = { [weak self, weak decorationNode, weak transitionNode] _ in
|
||||
guard let decorationNode = decorationNode else {
|
||||
return
|
||||
}
|
||||
self?.additionalAnimationNodes.removeAll(where: { $0 === decorationNode })
|
||||
transitionNode?.remove(decorationNode: decorationNode)
|
||||
}
|
||||
additionalAnimationNode.isPlayingChanged = { [weak self, weak decorationNode, weak transitionNode] isPlaying in
|
||||
if !isPlaying {
|
||||
guard let decorationNode = decorationNode else {
|
||||
return
|
||||
}
|
||||
self?.additionalAnimationNodes.removeAll(where: { $0 === decorationNode })
|
||||
transitionNode?.remove(decorationNode: decorationNode)
|
||||
}
|
||||
}
|
||||
|
||||
self.additionalAnimationNodes.append(decorationNode)
|
||||
|
||||
additionalAnimationNode.visibility = true
|
||||
}
|
||||
}
|
||||
|
||||
private func removeAdditionalAnimations() {
|
||||
for decorationNode in self.additionalAnimationNodes {
|
||||
if let additionalAnimationNode = decorationNode.contentView.asyncdisplaykit_node as? AnimatedStickerNode {
|
||||
additionalAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak additionalAnimationNode] _ in
|
||||
additionalAnimationNode?.visibility = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func currentMessageEffect() -> AvailableMessageEffects.MessageEffect? {
|
||||
guard let item = self.item else {
|
||||
return nil
|
||||
}
|
||||
var messageEffect: AvailableMessageEffects.MessageEffect?
|
||||
for attribute in item.message.attributes {
|
||||
if let attribute = attribute as? EffectMessageAttribute {
|
||||
if let availableMessageEffects = item.associatedData.availableMessageEffects {
|
||||
for effect in availableMessageEffects.messageEffects {
|
||||
if effect.id == attribute.id {
|
||||
messageEffect = effect
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return messageEffect
|
||||
}
|
||||
|
||||
private func playMessageEffect(force: Bool) {
|
||||
if let messageEffect = self.currentMessageEffect() {
|
||||
self.playPremiumStickerAnimation(effect: messageEffect, force: force)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateVisibility() {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
}
|
||||
|
||||
let isPlaying = self.visibilityStatus == true && !self.forceStopAnimations
|
||||
if !isPlaying {
|
||||
self.removeAdditionalAnimations()
|
||||
}
|
||||
|
||||
var alreadySeen = true
|
||||
if item.message.flags.contains(.Incoming) {
|
||||
if let unreadRange = item.controllerInteraction.unreadMessageRange[UnreadMessageRangeKey(peerId: item.message.id.peerId, namespace: item.message.id.namespace)] {
|
||||
if unreadRange.contains(item.message.id.id) {
|
||||
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
|
||||
alreadySeen = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if self.didChangeFromPendingToSent {
|
||||
if !item.controllerInteraction.seenOneTimeAnimatedMedia.contains(item.message.id) {
|
||||
alreadySeen = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !alreadySeen {
|
||||
item.controllerInteraction.seenOneTimeAnimatedMedia.insert(item.message.id)
|
||||
|
||||
self.playMessageEffect(force: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +295,7 @@ public class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.message.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
@ -573,6 +574,13 @@ public class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.dateAndStatusNode.isHidden {
|
||||
return self.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.dateAndStatusNode.supernode != nil, let result = self.dateAndStatusNode.hitTest(self.view.convert(point, to: self.dateAndStatusNode.view), with: event) {
|
||||
return result
|
||||
|
@ -59,6 +59,8 @@ private final class StatusReactionNode: ASDisplayNode {
|
||||
private var resolvedFile: TelegramMediaFile?
|
||||
private var fileDisposable: Disposable?
|
||||
|
||||
private var alternativeTextView: ImmediateTextView?
|
||||
|
||||
override init() {
|
||||
self.iconView = ReactionIconView()
|
||||
|
||||
@ -72,66 +74,11 @@ private final class StatusReactionNode: ASDisplayNode {
|
||||
self.fileDisposable?.dispose()
|
||||
}
|
||||
|
||||
func update(context: AccountContext, type: ChatMessageDateAndStatusType, value: MessageReaction.Reaction, file: TelegramMediaFile?, fileId: Int64?, isSelected: Bool, count: Int, theme: PresentationTheme, wallpaper: TelegramWallpaper, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, animated: Bool) {
|
||||
func update(context: AccountContext, type: ChatMessageDateAndStatusType, value: MessageReaction.Reaction, file: TelegramMediaFile?, fileId: Int64?, alternativeText: String, isSelected: Bool, count: Int, theme: PresentationTheme, wallpaper: TelegramWallpaper, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, animated: Bool) {
|
||||
if self.value != value {
|
||||
self.value = value
|
||||
|
||||
let boundingImageSize = CGSize(width: 14.0, height: 14.0)
|
||||
/*let defaultImageSize = CGSize(width: boundingImageSize.width + floor(boundingImageSize.width * 0.5 * 2.0), height: boundingImageSize.height + floor(boundingImageSize.height * 0.5 * 2.0))
|
||||
let imageSize: CGSize
|
||||
if let file = file {
|
||||
self.iconImageDisposable.set((reactionStaticImage(context: context, animation: file, pixelSize: CGSize(width: 72.0, height: 72.0), queue: sharedReactionStaticImage)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if data.isComplete, let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
if let image = UIImage(data: dataValue) {
|
||||
strongSelf.iconView.imageView.image = image
|
||||
}
|
||||
}
|
||||
}))
|
||||
imageSize = file.dimensions?.cgSize.aspectFitted(defaultImageSize) ?? defaultImageSize
|
||||
|
||||
self.fileDisposable?.dispose()
|
||||
self.fileDisposable = nil
|
||||
} else if let fileId = fileId {
|
||||
self.fileDisposable?.dispose()
|
||||
self.fileDisposable = nil
|
||||
|
||||
imageSize = boundingImageSize
|
||||
|
||||
if let resolvedFile = self.resolvedFile, resolvedFile.fileId.id == fileId {
|
||||
} else {
|
||||
self.fileDisposable = (context.engine.stickers.resolveInlineStickers(fileIds: [fileId])
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let strongSelf = self, let file = result[fileId] else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.resolvedFile = file
|
||||
|
||||
strongSelf.iconImageDisposable.set((reactionStaticImage(context: context, animation: file, pixelSize: CGSize(width: 72.0, height: 72.0), queue: sharedReactionStaticImage)
|
||||
|> deliverOnMainQueue).start(next: { data in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if data.isComplete, let dataValue = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
if let image = UIImage(data: dataValue) {
|
||||
strongSelf.iconView.imageView.image = image
|
||||
}
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
} else {
|
||||
imageSize = defaultImageSize
|
||||
|
||||
self.fileDisposable?.dispose()
|
||||
self.fileDisposable = nil
|
||||
}*/
|
||||
let boundingImageSize = CGSize(width: 8.0, height: 8.0)
|
||||
|
||||
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingImageSize.width - boundingImageSize.width) / 2.0), y: floorToScreenPixels((boundingImageSize.height - boundingImageSize.height) / 2.0)), size: boundingImageSize)
|
||||
self.iconView.frame = iconFrame
|
||||
@ -172,6 +119,21 @@ private final class StatusReactionNode: ASDisplayNode {
|
||||
reaction: value,
|
||||
transition: .immediate
|
||||
)
|
||||
if let alternativeTextView = self.alternativeTextView {
|
||||
self.alternativeTextView = nil
|
||||
alternativeTextView.removeFromSuperview()
|
||||
}
|
||||
} else {
|
||||
let alternativeTextView: ImmediateTextView
|
||||
if let current = self.alternativeTextView {
|
||||
alternativeTextView = current
|
||||
} else {
|
||||
alternativeTextView = ImmediateTextView()
|
||||
self.view.addSubview(alternativeTextView)
|
||||
}
|
||||
alternativeTextView.attributedText = NSAttributedString(string: alternativeText, font: Font.regular(10.0), textColor: .black)
|
||||
let alternativeTextSize = alternativeTextView.updateLayout(CGSize(width: 100.0, height: 100.0))
|
||||
alternativeTextView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((boundingImageSize.width - alternativeTextSize.width) / 2.0), y: floorToScreenPixels((boundingImageSize.height - alternativeTextSize.height) / 2.0)), size: alternativeTextSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -230,6 +192,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
var reactionPeers: [(MessageReaction.Reaction, EnginePeer)]
|
||||
var displayAllReactionPeers: Bool
|
||||
var areReactionsTags: Bool
|
||||
var messageEffect: AvailableMessageEffects.MessageEffect?
|
||||
var replyCount: Int
|
||||
var isPinned: Bool
|
||||
var hasAutoremove: Bool
|
||||
@ -252,6 +215,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
reactionPeers: [(MessageReaction.Reaction, EnginePeer)],
|
||||
displayAllReactionPeers: Bool,
|
||||
areReactionsTags: Bool,
|
||||
messageEffect: AvailableMessageEffects.MessageEffect?,
|
||||
replyCount: Int,
|
||||
isPinned: Bool,
|
||||
hasAutoremove: Bool,
|
||||
@ -273,6 +237,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
self.reactionPeers = reactionPeers
|
||||
self.displayAllReactionPeers = displayAllReactionPeers
|
||||
self.areReactionsTags = areReactionsTags
|
||||
self.messageEffect = messageEffect
|
||||
self.replyCount = replyCount
|
||||
self.isPinned = isPinned
|
||||
self.hasAutoremove = hasAutoremove
|
||||
@ -292,7 +257,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
private var impressionIcon: ASImageNode?
|
||||
private var reactionNodes: [MessageReaction.Reaction: StatusReactionNode] = [:]
|
||||
private let reactionButtonsContainer = ReactionButtonsAsyncLayoutContainer()
|
||||
private var reactionCountNode: TextNode?
|
||||
private var reactionButtonNode: HighlightTrackingButtonNode?
|
||||
private var repliesIcon: ASImageNode?
|
||||
private var selfExpiringIcon: ASImageNode?
|
||||
@ -356,7 +320,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
let currentTheme = self.theme
|
||||
|
||||
let makeReplyCountLayout = TextNode.asyncLayout(self.replyCountNode)
|
||||
let makeReactionCountLayout = TextNode.asyncLayout(self.reactionCountNode)
|
||||
|
||||
let reactionButtonsContainer = self.reactionButtonsContainer
|
||||
|
||||
@ -679,35 +642,11 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
|
||||
var replyCountLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
|
||||
let reactionSize: CGFloat = 17.0
|
||||
var reactionCountLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
let reactionSize: CGFloat = 8.0
|
||||
let reactionSpacing: CGFloat = 2.0
|
||||
let reactionTrailingSpacing: CGFloat = 6.0
|
||||
|
||||
var reactionInset: CGFloat = 0.0
|
||||
if arguments.layoutInput.displayInlineReactions, !arguments.reactions.isEmpty {
|
||||
reactionInset = -1.0 + CGFloat(arguments.reactions.count) * reactionSize + CGFloat(arguments.reactions.count - 1) * reactionSpacing + reactionTrailingSpacing
|
||||
|
||||
var count = 0
|
||||
for reaction in arguments.reactions {
|
||||
count += Int(reaction.count)
|
||||
}
|
||||
|
||||
let countString: String
|
||||
if count > 1000000 {
|
||||
countString = "\(count / 1000000)M"
|
||||
} else if count > 1000 {
|
||||
countString = "\(count / 1000)K"
|
||||
} else {
|
||||
countString = "\(count)"
|
||||
}
|
||||
|
||||
if count > arguments.reactions.count {
|
||||
let layoutAndApply = makeReactionCountLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: countString, font: dateFont, textColor: dateColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: 100.0)))
|
||||
reactionInset += layoutAndApply.0.size.width + 4.0
|
||||
reactionCountLayoutAndApply = layoutAndApply
|
||||
}
|
||||
}
|
||||
|
||||
if arguments.replyCount > 0 {
|
||||
let countString: String
|
||||
@ -726,6 +665,10 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
reactionInset += 12.0
|
||||
}
|
||||
|
||||
if arguments.messageEffect != nil {
|
||||
reactionInset += 13.0
|
||||
}
|
||||
|
||||
leftInset += reactionInset
|
||||
|
||||
let layoutSize = CGSize(width: leftInset + impressionWidth + date.size.width + statusWidth + backgroundInsets.left + backgroundInsets.right, height: date.size.height + backgroundInsets.top + backgroundInsets.bottom)
|
||||
@ -1145,59 +1088,34 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
var reactionOffset: CGFloat = leftOffset + leftInset - reactionInset + backgroundInsets.left
|
||||
if arguments.layoutInput.displayInlineReactions {
|
||||
|
||||
if let messageEffect = arguments.messageEffect {
|
||||
var validReactions = Set<MessageReaction.Reaction>()
|
||||
for reaction in arguments.reactions.sorted(by: { lhs, rhs in
|
||||
if lhs.isSelected != rhs.isSelected {
|
||||
if lhs.isSelected {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if let lhsIndex = lhs.chosenOrder, let rhsIndex = rhs.chosenOrder {
|
||||
return lhsIndex < rhsIndex
|
||||
} else {
|
||||
return lhs.count > rhs.count
|
||||
}
|
||||
}
|
||||
}) {
|
||||
do {
|
||||
let node: StatusReactionNode
|
||||
var animateNode = true
|
||||
if let current = strongSelf.reactionNodes[reaction.value] {
|
||||
if let current = strongSelf.reactionNodes[.custom(messageEffect.id)] {
|
||||
node = current
|
||||
} else {
|
||||
animateNode = false
|
||||
node = StatusReactionNode()
|
||||
strongSelf.reactionNodes[reaction.value] = node
|
||||
strongSelf.reactionNodes[.custom(messageEffect.id)] = node
|
||||
}
|
||||
validReactions.insert(reaction.value)
|
||||
validReactions.insert(.custom(messageEffect.id))
|
||||
|
||||
var centerAnimation: TelegramMediaFile?
|
||||
var reactionFileId: Int64?
|
||||
|
||||
switch reaction.value {
|
||||
case .builtin:
|
||||
if let availableReactions = arguments.availableReactions {
|
||||
for availableReaction in availableReactions.reactions {
|
||||
if availableReaction.value == reaction.value {
|
||||
centerAnimation = availableReaction.centerAnimation
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .custom(fileId):
|
||||
reactionFileId = fileId
|
||||
}
|
||||
centerAnimation = messageEffect.staticIcon
|
||||
|
||||
node.update(
|
||||
context: arguments.context,
|
||||
type: arguments.type,
|
||||
value: reaction.value,
|
||||
value: .custom(messageEffect.id),
|
||||
file: centerAnimation,
|
||||
fileId: reactionFileId,
|
||||
isSelected: reaction.isSelected,
|
||||
count: Int(reaction.count),
|
||||
fileId: centerAnimation?.fileId.id,
|
||||
alternativeText: messageEffect.emoticon,
|
||||
isSelected: false,
|
||||
count: 0,
|
||||
theme: arguments.presentationData.theme.theme,
|
||||
wallpaper: arguments.presentationData.theme.wallpaper,
|
||||
animationCache: arguments.animationCache,
|
||||
@ -1210,7 +1128,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset + verticalInset), size: CGSize(width: reactionSize, height: reactionSize))
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset, y: backgroundInsets.top + offset + 3.0 + UIScreenPixel + verticalInset), size: CGSize(width: reactionSize, height: reactionSize))
|
||||
if animateNode {
|
||||
animation.animator.updateFrame(layer: node.layer, frame: nodeFrame, completion: nil)
|
||||
} else {
|
||||
@ -1259,30 +1177,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let (layout, apply) = reactionCountLayoutAndApply {
|
||||
let node = apply()
|
||||
if strongSelf.reactionCountNode !== node {
|
||||
strongSelf.reactionCountNode?.removeFromSupernode()
|
||||
strongSelf.addSubnode(node)
|
||||
strongSelf.reactionCountNode = node
|
||||
if animation.isAnimated {
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
|
||||
}
|
||||
}
|
||||
let nodeFrame = CGRect(origin: CGPoint(x: reactionOffset - 4.0, y: backgroundInsets.top + 1.0 + offset + verticalInset), size: layout.size)
|
||||
animation.animator.updateFrame(layer: node.layer, frame: nodeFrame, completion: nil)
|
||||
reactionOffset += 1.0 + layout.size.width + 4.0
|
||||
} else if let reactionCountNode = strongSelf.reactionCountNode {
|
||||
strongSelf.reactionCountNode = nil
|
||||
if animation.isAnimated {
|
||||
reactionCountNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak reactionCountNode] _ in
|
||||
reactionCountNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
reactionCountNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
if let currentRepliesIcon = currentRepliesIcon {
|
||||
currentRepliesIcon.displaysAsynchronously = false
|
||||
if currentRepliesIcon.image !== repliesImage {
|
||||
@ -1363,11 +1257,6 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
public func reactionView(value: MessageReaction.Reaction) -> UIView? {
|
||||
for (id, node) in self.reactionNodes {
|
||||
if id == value {
|
||||
return node.iconView
|
||||
}
|
||||
}
|
||||
for (key, button) in self.reactionButtonsContainer.buttons {
|
||||
if key == value {
|
||||
return button.view.iconView
|
||||
@ -1376,6 +1265,13 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func messageEffectTargetView() -> UIView? {
|
||||
for (_, node) in self.reactionNodes {
|
||||
return node.iconView
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
for (_, button) in self.reactionButtonsContainer.buttons {
|
||||
if button.view.frame.contains(point) {
|
||||
|
@ -249,4 +249,11 @@ public class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.interactiveFileNode.dateAndStatusNode.isHidden {
|
||||
return self.interactiveFileNode.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -149,4 +149,11 @@ public final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNod
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if let statusNode = self.contentNode.statusNode, !statusNode.isHidden {
|
||||
return statusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -528,6 +528,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
@ -863,6 +864,13 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode,
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.dateAndStatusNode.isHidden {
|
||||
return self.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.dateAndStatusNode.supernode != nil, let result = self.dateAndStatusNode.hitTest(self.view.convert(point, to: self.dateAndStatusNode.view), with: event) {
|
||||
return result
|
||||
|
@ -458,6 +458,13 @@ public class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentN
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.interactiveVideoNode.dateAndStatusNode.isHidden {
|
||||
return self.interactiveVideoNode.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func targetForStoryTransition(id: StoryId) -> UIView? {
|
||||
return self.interactiveVideoNode.targetForStoryTransition(id: id)
|
||||
}
|
||||
|
@ -943,6 +943,7 @@ public final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: arguments.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: arguments.message.areReactionsTags(accountPeerId: arguments.context.account.peerId),
|
||||
messageEffect: arguments.message.messageEffect(availableMessageEffects: arguments.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: arguments.isPinned && !arguments.associatedData.isInPinnedListMode,
|
||||
hasAutoremove: arguments.message.isSelfExpiring,
|
||||
|
@ -579,6 +579,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
|
@ -874,6 +874,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
reactionPeers: dateAndStatus.dateReactionPeers,
|
||||
displayAllReactionPeers: message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: message.areReactionsTags(accountPeerId: context.account.peerId),
|
||||
messageEffect: message.messageEffect(availableMessageEffects: associatedData.availableMessageEffects),
|
||||
replyCount: dateAndStatus.dateReplies,
|
||||
isPinned: dateAndStatus.isPinned,
|
||||
hasAutoremove: message.isSelfExpiring,
|
||||
|
@ -145,4 +145,11 @@ public final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContent
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if let statusNode = self.contentNode.statusNode, !statusNode.isHidden {
|
||||
return statusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -282,6 +282,7 @@ public class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
@ -540,4 +541,11 @@ public class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.dateAndStatusNode.isHidden {
|
||||
return self.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -510,4 +510,11 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.interactiveImageNode.dateAndStatusNode.isHidden {
|
||||
return self.interactiveImageNode.dateAndStatusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -1095,6 +1095,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
@ -1786,4 +1787,11 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if !self.statusNode.isHidden {
|
||||
return self.statusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,7 @@ public class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNod
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
|
@ -631,6 +631,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.message.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.message.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && !isReplyThread,
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
|
@ -578,6 +578,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
reactionPeers: dateReactionsAndPeers.peers,
|
||||
displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser,
|
||||
areReactionsTags: item.topMessage.areReactionsTags(accountPeerId: item.context.account.peerId),
|
||||
messageEffect: item.topMessage.messageEffect(availableMessageEffects: item.associatedData.availableMessageEffects),
|
||||
replyCount: dateReplies,
|
||||
isPinned: item.message.tags.contains(.pinned) && (!item.associatedData.isInPinnedListMode || isReplyThread),
|
||||
hasAutoremove: item.message.isSelfExpiring,
|
||||
@ -1358,6 +1359,13 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
if let statusNode = self.statusNode, !statusNode.isHidden {
|
||||
return statusNode.messageEffectTargetView()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override public func getStatusNode() -> ASDisplayNode? {
|
||||
return self.statusNode
|
||||
}
|
||||
|
@ -749,4 +749,8 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent
|
||||
override public func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
return self.contentNode.reactionTargetView(value: value)
|
||||
}
|
||||
|
||||
override public func messageEffectTargetView() -> UIView? {
|
||||
return self.contentNode.messageEffectTargetView()
|
||||
}
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
if let context = self?.context, let navigationController = self?.getNavigationController() {
|
||||
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: threadId, messageId: nil, navigationController: navigationController, activateInput: nil, scrollToEndIfExists: false, keepStack: .always).startStandalone()
|
||||
}
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _, _ in return false
|
||||
}, tapMessage: nil, clickThroughMessage: { }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _, _ in }, sendMessage: { _ in }, sendSticker: { _, _, _, _, _, _, _, _, _ in return false }, sendEmoji: { _, _, _ in }, sendGif: { _, _, _, _, _ in return false }, sendBotContextResultAsGif: { _, _, _, _, _, _ in return false
|
||||
}, requestMessageActionCallback: { [weak self] messageId, _, _, _ in
|
||||
guard let self else {
|
||||
return
|
||||
|
@ -130,7 +130,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
return self.id
|
||||
}
|
||||
|
||||
func item(context: AccountContext, peer: Peer, controllerInteraction: ChatControllerInteraction, chatThemes: [TelegramTheme], availableReactions: AvailableReactions?) -> ListViewItem {
|
||||
func item(context: AccountContext, peer: Peer, controllerInteraction: ChatControllerInteraction, chatThemes: [TelegramTheme], availableReactions: AvailableReactions?, availableMessageEffects: AvailableMessageEffects?) -> ListViewItem {
|
||||
switch self.entry.event.action {
|
||||
case let .changeTitle(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -143,7 +143,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.titleUpdated(title: new)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeAbout(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -174,14 +174,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let attributes: [MessageAttribute] = []
|
||||
let prevMessage = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: prev, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: new, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
}
|
||||
case let .changeUsername(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -212,7 +212,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var previousAttributes: [MessageAttribute] = []
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -231,7 +231,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let prevMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: prevText, attributes: previousAttributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
}
|
||||
case let .changeUsernames(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -262,7 +262,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var previousAttributes: [MessageAttribute] = []
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -300,7 +300,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let prevMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: prevText, attributes: previousAttributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
}
|
||||
case let .changePhoto(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -319,7 +319,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.photoUpdated(image: photo)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleInvites(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -346,7 +346,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleSignatures(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -373,7 +373,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updatePinned(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -404,7 +404,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
if let message = message {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -428,7 +428,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
} else {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -450,7 +450,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
}
|
||||
case let .editMessage(prev, message):
|
||||
@ -495,7 +495,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -518,7 +518,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
}
|
||||
case let .deleteMessage(message):
|
||||
switch self.id.contentIndex {
|
||||
@ -579,7 +579,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -628,7 +628,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: message.id.id), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: additionalContent)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: additionalContent)
|
||||
}
|
||||
case .participantJoin, .participantLeave:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -646,7 +646,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
action = TelegramMediaActionType.removedMembers(peerIds: [self.entry.event.peerId])
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantInvite(participant):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -663,7 +663,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action: TelegramMediaActionType
|
||||
action = TelegramMediaActionType.addedMembers(peerIds: [participant.peer.id])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantToggleBan(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -794,7 +794,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantToggleAdmin(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1034,7 +1034,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeStickerPack(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1063,7 +1063,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .togglePreHistoryHidden(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1093,7 +1093,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updateDefaultBannedRights(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1152,7 +1152,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .pollStopped(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -1180,7 +1180,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1203,7 +1203,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil)
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil), additionalContent: nil)
|
||||
}
|
||||
case let .linkedPeerUpdated(previous, updated):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -1259,7 +1259,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeGeoLocation(_, updated):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1281,12 +1281,12 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let mediaMap = TelegramMediaMap(latitude: updated.latitude, longitude: updated.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: text, attributes: [], media: [mediaMap], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
} else {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
case let .updateSlowmode(_, newValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -1317,7 +1317,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .startGroupCall, .endGroupCall:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1354,7 +1354,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .groupCallUpdateParticipantMuteStatus(participantId, isMuted):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1388,7 +1388,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .updateGroupCallSettings(joinMuted):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1417,7 +1417,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .groupCallUpdateParticipantVolume(participantId, volume):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1448,7 +1448,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .deleteExportedInvitation(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1474,7 +1474,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .revokeExportedInvitation(invite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1500,7 +1500,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .editExportedInvitation(_, updatedInvite):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1526,7 +1526,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantJoinedViaInvite(invite, joinedViaFolderLink):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1557,7 +1557,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeHistoryTTL(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1588,7 +1588,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeAvailableReactions(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1659,7 +1659,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeTheme(_, updatedValue):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1690,7 +1690,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .participantJoinByRequest(invite, approvedBy):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1730,7 +1730,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleCopyProtection(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1757,7 +1757,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .sendMessage(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -1782,7 +1782,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -1805,7 +1805,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
peers[peer.id] = peer
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: message.threadId, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: message.associatedMessages, associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: message.associatedThreadInfo, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
case let .createTopic(info):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -1825,7 +1825,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}, to: &text, entities: &entities)
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .deleteTopic(info):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1846,7 +1846,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .editTopic(prevInfo, newInfo):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1919,7 +1919,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .pinTopic(prevInfo, newInfo):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1957,7 +1957,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleForum(isForum):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1978,7 +1978,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .toggleAntiSpam(isEnabled):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -1999,7 +1999,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeNameColor(_, _, updatedColor, updatedIcon):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -2068,7 +2068,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: TelegramMediaActionType.CustomTextAttributes(attributes: additionalAttributes))
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeProfileColor(_, _, updatedColor, updatedIcon):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -2147,7 +2147,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: TelegramMediaActionType.CustomTextAttributes(attributes: additionalAttributes))
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeStatus(_, status):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -2182,7 +2182,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeWallpaper(_, wallpaper):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -2210,7 +2210,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil, chatThemes: chatThemes), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil, chatThemes: chatThemes), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
case let .changeEmojiPack(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -2239,7 +2239,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities, additionalAttributes: nil)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
return ChatMessageItemImpl(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadPeerId: nil, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2321,8 +2321,8 @@ func chatRecentActionsHistoryPreparedTransition(from fromEntries: [ChatRecentAct
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdatesReversed(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, peer: peer, controllerInteraction: controllerInteraction, chatThemes: chatThemes, availableReactions: availableReactions), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, peer: peer, controllerInteraction: controllerInteraction, chatThemes: chatThemes, availableReactions: availableReactions), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, peer: peer, controllerInteraction: controllerInteraction, chatThemes: chatThemes, availableReactions: availableReactions, availableMessageEffects: nil), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, peer: peer, controllerInteraction: controllerInteraction, chatThemes: chatThemes, availableReactions: availableReactions, availableMessageEffects: nil), directionHint: nil) }
|
||||
|
||||
return ChatRecentActionsHistoryTransition(filteredEntries: toEntries, type: type, deletions: deletions, insertions: insertions, updates: updates, canLoadEarlier: canLoadEarlier, displayingResults: displayingResults, searchResultsState: searchResultsState, synchronous: !toggledDeletedMessageIds.isEmpty, isEmpty: toEntries.isEmpty)
|
||||
}
|
||||
|
@ -421,40 +421,33 @@ public func topMessageReactions(context: AccountContext, message: Message, subPe
|
||||
}
|
||||
|
||||
public func effectMessageReactions(context: AccountContext) -> Signal<[ReactionItem], NoError> {
|
||||
return context.engine.stickers.availableReactions()
|
||||
return context.engine.stickers.availableMessageEffects()
|
||||
|> take(1)
|
||||
|> map { availableReactions -> [ReactionItem] in
|
||||
guard let availableReactions else {
|
||||
|> map { availableMessageEffects -> [ReactionItem] in
|
||||
guard let availableMessageEffects else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result: [ReactionItem] = []
|
||||
var existingIds = Set<MessageReaction.Reaction>()
|
||||
var existingIds = Set<Int64>()
|
||||
|
||||
for reaction in availableReactions.reactions {
|
||||
guard let centerAnimation = reaction.centerAnimation else {
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if existingIds.contains(messageEffect.id) {
|
||||
continue
|
||||
}
|
||||
guard let aroundAnimation = reaction.aroundAnimation else {
|
||||
continue
|
||||
}
|
||||
if !reaction.isEnabled {
|
||||
continue
|
||||
}
|
||||
if existingIds.contains(reaction.value) {
|
||||
continue
|
||||
}
|
||||
existingIds.insert(reaction.value)
|
||||
existingIds.insert(messageEffect.id)
|
||||
|
||||
let mainFile: TelegramMediaFile = messageEffect.effectSticker
|
||||
|
||||
result.append(ReactionItem(
|
||||
reaction: ReactionItem.Reaction(rawValue: reaction.value),
|
||||
appearAnimation: reaction.appearAnimation,
|
||||
stillAnimation: reaction.selectAnimation,
|
||||
listAnimation: centerAnimation,
|
||||
largeListAnimation: reaction.activateAnimation,
|
||||
applicationAnimation: aroundAnimation,
|
||||
largeApplicationAnimation: reaction.effectAnimation,
|
||||
isCustom: false
|
||||
reaction: ReactionItem.Reaction(rawValue: .custom(messageEffect.id)),
|
||||
appearAnimation: mainFile,
|
||||
stillAnimation: mainFile,
|
||||
listAnimation: mainFile,
|
||||
largeListAnimation: mainFile,
|
||||
applicationAnimation: nil,
|
||||
largeApplicationAnimation: nil,
|
||||
isCustom: true
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,14 @@ public struct OpenMessageParams {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ChatSendMessageEffect {
|
||||
public let id: Int64
|
||||
|
||||
public init(id: Int64) {
|
||||
self.id = id
|
||||
}
|
||||
}
|
||||
|
||||
public final class ChatControllerInteraction: ChatControllerInteractionProtocol {
|
||||
public enum OpenPeerSource {
|
||||
case `default`
|
||||
@ -154,7 +162,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
public let tapMessage: ((Message) -> Void)?
|
||||
public let clickThroughMessage: () -> Void
|
||||
public let toggleMessagesSelection: ([MessageId], Bool) -> Void
|
||||
public let sendCurrentMessage: (Bool) -> Void
|
||||
public let sendCurrentMessage: (Bool, ChatSendMessageEffect?) -> Void
|
||||
public let sendMessage: (String) -> Void
|
||||
public let sendSticker: (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool
|
||||
public let sendEmoji: (String, ChatTextInputTextCustomEmojiAttribute, Bool) -> Void
|
||||
@ -279,7 +287,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
|
||||
tapMessage: ((Message) -> Void)?,
|
||||
clickThroughMessage: @escaping () -> Void,
|
||||
toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void,
|
||||
sendCurrentMessage: @escaping (Bool) -> Void,
|
||||
sendCurrentMessage: @escaping (Bool, ChatSendMessageEffect?) -> Void,
|
||||
sendMessage: @escaping (String) -> Void,
|
||||
sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool,
|
||||
sendEmoji: @escaping (String, ChatTextInputTextCustomEmojiAttribute, Bool) -> Void,
|
||||
|
@ -2163,4 +2163,140 @@ public extension EmojiPagerContentComponent {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static func messageEffectsInputData(
|
||||
context: AccountContext,
|
||||
animationCache: AnimationCache,
|
||||
animationRenderer: MultiAnimationRenderer,
|
||||
hasSearch: Bool,
|
||||
hideBackground: Bool = false
|
||||
) -> Signal<EmojiPagerContentComponent, NoError> {
|
||||
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||
let isPremiumDisabled = premiumConfiguration.isPremiumDisabled
|
||||
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
|
||||
let searchCategories: Signal<EmojiSearchCategories?, NoError> = .single(nil)
|
||||
|
||||
return combineLatest(
|
||||
hasPremium(context: context, chatPeerId: nil, premiumIfSavedMessages: false),
|
||||
context.engine.stickers.availableMessageEffects(),
|
||||
searchCategories
|
||||
)
|
||||
|> map { hasPremium, availableMessageEffects, searchCategories -> EmojiPagerContentComponent in
|
||||
struct ItemGroup {
|
||||
var supergroupId: AnyHashable
|
||||
var id: AnyHashable
|
||||
var title: String?
|
||||
var subtitle: String?
|
||||
var actionButtonTitle: String?
|
||||
var isPremiumLocked: Bool
|
||||
var isFeatured: Bool
|
||||
var displayPremiumBadges: Bool
|
||||
var hasEdit: Bool
|
||||
var headerItem: EntityKeyboardAnimationData?
|
||||
var items: [EmojiPagerContentComponent.Item]
|
||||
}
|
||||
var itemGroups: [ItemGroup] = []
|
||||
var itemGroupIndexById: [AnyHashable: Int] = [:]
|
||||
|
||||
if let availableMessageEffects {
|
||||
var reactionEffects: [AvailableMessageEffects.MessageEffect] = []
|
||||
var stickerEffects: [AvailableMessageEffects.MessageEffect] = []
|
||||
for messageEffect in availableMessageEffects.messageEffects {
|
||||
if messageEffect.effectAnimation != nil {
|
||||
reactionEffects.append(messageEffect)
|
||||
} else {
|
||||
stickerEffects.append(messageEffect)
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0 ..< 2 {
|
||||
let groupId = i == 0 ? "reactions" : "stickers"
|
||||
for item in i == 0 ? reactionEffects : stickerEffects {
|
||||
if item.isPremium && isPremiumDisabled {
|
||||
continue
|
||||
}
|
||||
|
||||
let itemFile: TelegramMediaFile = item.effectSticker
|
||||
|
||||
var tintMode: Item.TintMode = .none
|
||||
if itemFile.isCustomTemplateEmoji {
|
||||
tintMode = .primary
|
||||
}
|
||||
|
||||
let animationData = EntityKeyboardAnimationData(file: itemFile, partialReference: .none)
|
||||
let resultItem = EmojiPagerContentComponent.Item(
|
||||
animationData: animationData,
|
||||
content: .animation(animationData),
|
||||
itemFile: itemFile,
|
||||
subgroupId: nil,
|
||||
icon: .none,
|
||||
tintMode: tintMode
|
||||
)
|
||||
|
||||
if let groupIndex = itemGroupIndexById[groupId] {
|
||||
itemGroups[groupIndex].items.append(resultItem)
|
||||
} else {
|
||||
itemGroupIndexById[groupId] = itemGroups.count
|
||||
//TODO:localize
|
||||
itemGroups.append(ItemGroup(supergroupId: groupId, id: groupId, title: i == 0 ? nil : "Message Effects", subtitle: nil, actionButtonTitle: nil, isPremiumLocked: false, isFeatured: false, displayPremiumBadges: false, hasEdit: false, headerItem: nil, items: [resultItem]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let warpContentsOnEdges: Bool = true
|
||||
|
||||
let allItemGroups = itemGroups.map { group -> EmojiPagerContentComponent.ItemGroup in
|
||||
let hasClear = false
|
||||
let isEmbedded = false
|
||||
|
||||
return EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: group.supergroupId,
|
||||
groupId: group.id,
|
||||
title: group.title,
|
||||
subtitle: group.subtitle,
|
||||
badge: nil,
|
||||
actionButtonTitle: group.actionButtonTitle,
|
||||
isFeatured: group.isFeatured,
|
||||
isPremiumLocked: group.isPremiumLocked,
|
||||
isEmbedded: isEmbedded,
|
||||
hasClear: hasClear,
|
||||
hasEdit: group.hasEdit,
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: group.displayPremiumBadges,
|
||||
headerItem: group.headerItem,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: group.items
|
||||
)
|
||||
}
|
||||
|
||||
return EmojiPagerContentComponent(
|
||||
id: "stickers",
|
||||
context: context,
|
||||
avatarPeer: nil,
|
||||
animationCache: animationCache,
|
||||
animationRenderer: animationRenderer,
|
||||
inputInteractionHolder: EmojiPagerContentComponent.InputInteractionHolder(),
|
||||
panelItemGroups: [],
|
||||
contentItemGroups: allItemGroups,
|
||||
itemLayoutType: .detailed,
|
||||
itemContentUniqueId: nil,
|
||||
searchState: .empty(hasResults: false),
|
||||
warpContentsOnEdges: warpContentsOnEdges,
|
||||
hideBackground: hideBackground,
|
||||
displaySearchWithPlaceholder: hasSearch ? strings.StickersSearch_SearchStickersPlaceholder : nil,
|
||||
searchCategories: searchCategories,
|
||||
searchInitiallyHidden: true,
|
||||
searchAlwaysActive: false,
|
||||
searchIsPlaceholderOnly: false,
|
||||
searchUnicodeEmojiOnly: false,
|
||||
emptySearchResults: nil,
|
||||
enableLongPress: false,
|
||||
selectedItems: Set(),
|
||||
customTintColor: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6562,7 +6562,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
contextItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
|
||||
contextItems.append(.separator)
|
||||
@ -6623,7 +6623,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
tipSignal: nil,
|
||||
dismissed: nil
|
||||
)
|
||||
c.pushItems(items: .single(items))
|
||||
c?.pushItems(items: .single(items))
|
||||
})))
|
||||
case .editing:
|
||||
menuItems.append(.action(ContextMenuActionItem(text: presentationData.strings.MediaEditor_ReplaceSticker, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replace"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
|
@ -396,7 +396,7 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.GroupInfo_ActionPromote, icon: { _ in
|
||||
return nil
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
action(member, .promote)
|
||||
})
|
||||
})))
|
||||
@ -406,7 +406,7 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.GroupInfo_ActionRestrict, icon: { _ in
|
||||
return nil
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
action(member, .restrict)
|
||||
})
|
||||
})))
|
||||
@ -414,7 +414,7 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Delete, textColor: .destructive, icon: { _ in
|
||||
return nil
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
action(member, .remove)
|
||||
})
|
||||
})))
|
||||
|
@ -2843,7 +2843,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self, let currentPeer = strongSelf.data?.peer, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
if let channel = currentPeer as? TelegramChannel, channel.flags.contains(.isForum), let threadId = message.threadId {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: currentPeer.id, threadId: threadId, messageId: message.id, navigationController: navigationController, activateInput: nil, scrollToEndIfExists: false, keepStack: .default).startStandalone()
|
||||
@ -2885,7 +2885,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if let linkForCopying = linkForCopying {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss(completion: {})
|
||||
c?.dismiss(completion: {})
|
||||
UIPasteboard.general.string = linkForCopying
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
@ -2897,7 +2897,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
} else if message.id.peerId.namespace != Namespaces.Peer.SecretChat && message.minAutoremoveOrClearTimeout == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.forwardMessages(messageIds: Set([message.id]))
|
||||
}
|
||||
@ -2909,7 +2909,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let presentationData = strongSelf.presentationData
|
||||
let peerId = strongSelf.peerId
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuDelete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, _ in
|
||||
c.setItems(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId))
|
||||
c?.setItems(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId))
|
||||
|> map { peer -> ContextController.Items in
|
||||
var items: [ContextMenuItem] = []
|
||||
let messageIds = [message.id]
|
||||
@ -2933,7 +2933,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
globalTitle = presentationData.strings.Conversation_DeleteMessagesForEveryone
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: globalTitle, textColor: .destructive, icon: { _ in nil }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone, nil, nil)
|
||||
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: Array(messageIds), type: .forEveryone).startStandalone()
|
||||
@ -2952,7 +2952,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: localOptionText, textColor: .destructive, icon: { _ in nil }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone, nil, nil)
|
||||
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: Array(messageIds), type: .forLocalPeer).startStandalone()
|
||||
@ -2970,7 +2970,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatInterfaceInteraction.toggleMessagesSelection([message.id], true)
|
||||
strongSelf.expandTabs(animated: true)
|
||||
@ -3005,7 +3005,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self, let currentPeer = strongSelf.data?.peer, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
if let channel = currentPeer as? TelegramChannel, channel.flags.contains(.isForum), let threadId = message.threadId {
|
||||
let _ = strongSelf.context.sharedContext.navigateToForumThread(context: strongSelf.context, peerId: currentPeer.id, threadId: threadId, messageId: message.id, navigationController: navigationController, activateInput: nil, scrollToEndIfExists: false, keepStack: .default).startStandalone()
|
||||
@ -3049,7 +3049,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
} else if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.forwardMessages(messageIds: [message.id])
|
||||
}
|
||||
@ -3059,7 +3059,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if actions.options.contains(.deleteLocally) || actions.options.contains(.deleteGlobally) {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuDelete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.setItems(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId))
|
||||
c?.setItems(context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId))
|
||||
|> map { peer -> ContextController.Items in
|
||||
var items: [ContextMenuItem] = []
|
||||
let messageIds = [message.id]
|
||||
@ -3083,7 +3083,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
globalTitle = strongSelf.presentationData.strings.Conversation_DeleteMessagesForEveryone
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: globalTitle, textColor: .destructive, icon: { _ in nil }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone, nil, nil)
|
||||
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: Array(messageIds), type: .forEveryone).startStandalone()
|
||||
@ -3102,7 +3102,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: localOptionText, textColor: .destructive, icon: { _ in nil }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone, nil, nil)
|
||||
let _ = strongSelf.context.engine.messages.deleteMessagesInteractively(messageIds: Array(messageIds), type: .forLocalPeer).startStandalone()
|
||||
@ -3167,7 +3167,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false)
|
||||
}
|
||||
strongSelf.paneContainerNode.updateSelectedMessageIds(strongSelf.state.selectedMessageIds, animated: true)
|
||||
}, sendCurrentMessage: { _ in
|
||||
}, sendCurrentMessage: { _, _ in
|
||||
}, sendMessage: { _ in
|
||||
}, sendSticker: { _, _, _, _, _, _, _, _, _ in
|
||||
return false
|
||||
@ -5406,7 +5406,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
subItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -5437,7 +5437,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self?.openCustomMute()
|
||||
})))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
@ -5949,7 +5949,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
subItems.append(.action(ContextMenuActionItem(text: strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -6003,9 +6003,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
self.controller?.view.endEditing(true)
|
||||
}, contentContext: nil, progress: nil, completion: nil)
|
||||
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
}, action: nil as ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6014,7 +6014,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.PeerInfo_ClearMessages, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: user, chatPeer: user)
|
||||
if let c {
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: user, chatPeer: user)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6149,7 +6151,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
subItems.append(.action(ContextMenuActionItem(text: strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -6210,9 +6212,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
self.controller?.view.endEditing(true)
|
||||
}, contentContext: nil, progress: nil, completion: nil)
|
||||
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
}, action: nil as ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6221,7 +6223,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.PeerInfo_ClearMessages, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: channel, chatPeer: channel)
|
||||
if let c {
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: channel, chatPeer: channel)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6284,7 +6288,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
subItems.append(.action(ContextMenuActionItem(text: strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -6338,9 +6342,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
self.controller?.view.endEditing(true)
|
||||
}, contentContext: nil, progress: nil, completion: nil)
|
||||
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
}, action: nil as ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6370,7 +6374,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.PeerInfo_ClearMessages, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: group, chatPeer: group)
|
||||
if let c {
|
||||
self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: group, chatPeer: group)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
@ -6646,7 +6652,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
subItems.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -6664,7 +6670,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: title, textLayout: .multiline, textFont: .small, icon: { _ in
|
||||
return nil
|
||||
}, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
}, action: nil as ((ContextControllerProtocol?, @escaping (ContextMenuActionResult) -> Void) -> Void)?)))
|
||||
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { [weak self] type in
|
||||
guard let strongSelf = self else {
|
||||
@ -6953,7 +6959,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if self.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_UsernameActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -6963,7 +6969,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_UsernameActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7029,7 +7035,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if self.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BioActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7056,7 +7062,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
copyText = self.presentationData.strings.ChannelProfile_AboutActionCopy
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: copyText, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7064,7 +7070,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let (canTranslate, language) = canTranslateText(context: self.context, text: bioText, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: false, ignoredLanguages: translationSettings.ignoredLanguages)
|
||||
if canTranslate {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuTranslate, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Translate"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7119,7 +7125,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if self.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_HoursActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7130,7 +7136,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_HoursActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7152,14 +7158,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
action: noAction
|
||||
)))
|
||||
subItems.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_HoursRemoveConfirmation_Action, textColor: .destructive, icon: { _ in nil }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self.context.engine.accountData.updateAccountBusinessHours(businessHours: nil).startStandalone()
|
||||
}
|
||||
})))
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -7199,7 +7205,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if businessLocation.coordinates != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_LocationActionOpen, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LocationSmall"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7210,7 +7216,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if !businessLocation.address.isEmpty {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_LocationActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7218,7 +7224,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if self.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_LocationActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7242,14 +7248,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
action: noAction
|
||||
)))
|
||||
subItems.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_LocationRemoveConfirmation_Action, textColor: .destructive, icon: { _ in nil }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self.context.engine.accountData.updateAccountBusinessLocation(businessLocation: nil).startStandalone()
|
||||
}
|
||||
})))
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -7292,7 +7298,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if self.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BirthdayActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7304,7 +7310,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.MyProfile_BirthdayActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7391,7 +7397,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if strongSelf.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.MyProfile_PhoneActionEdit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -7403,12 +7409,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone, formattedPhoneNumber == formatPhoneNumber(context: strongSelf.context, number: peerPhoneNumber) {
|
||||
if !strongSelf.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_TelegramCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
telegramCallAction(false)
|
||||
}
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_TelegramVideoCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/VideoCall"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
telegramCallAction(true)
|
||||
}
|
||||
})))
|
||||
@ -7416,7 +7422,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if !formattedPhoneNumber.hasPrefix("+888") {
|
||||
if !strongSelf.isMyProfile {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_PhoneCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PhoneCall"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
phoneCallAction()
|
||||
}
|
||||
})))
|
||||
@ -7425,7 +7431,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
isAnonymousNumber = true
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.MyProfile_PhoneActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
})))
|
||||
@ -7434,7 +7440,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if !strongSelf.isMyProfile {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_PhoneCall, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/PhoneCall"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
phoneCallAction()
|
||||
}
|
||||
}))
|
||||
@ -7445,7 +7451,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.MyProfile_PhoneActionCopy, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss {
|
||||
c?.dismiss {
|
||||
copyAction()
|
||||
}
|
||||
}))
|
||||
@ -8002,7 +8008,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { (c, _) in
|
||||
if let backAction = backAction {
|
||||
if let c, let backAction = backAction {
|
||||
backAction(c)
|
||||
}
|
||||
})))
|
||||
|
@ -1859,7 +1859,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
}
|
||||
|
||||
/*items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryList_ItemAction_Edit, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -1872,7 +1872,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
|
||||
if !item.isForwardingDisabled, case .everyone = item.privacy?.base {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryList_ItemAction_Forward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -1914,7 +1914,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
|
||||
|
||||
if canManage {
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.StoryList_ItemAction_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ public func presentPeerReportOptions(
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { (c, _) in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
|
@ -691,8 +691,8 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
hasEntityKeyboard = true
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputNode.textView, canSendWhenOnline: false, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode in
|
||||
let controller = makeChatSendMessageActionSheetController(context: strongSelf.context, peerId: strongSelf.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputNode.textView, emojiViewProvider: textInputPanelNode.emojiViewProvider, canSendWhenOnline: false, completion: {
|
||||
}, sendMessage: { [weak textInputPanelNode] mode, _ in
|
||||
switch mode {
|
||||
case .generic:
|
||||
textInputPanelNode?.sendMessage(.generic)
|
||||
@ -701,10 +701,9 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
case .whenOnline:
|
||||
textInputPanelNode?.sendMessage(.whenOnline)
|
||||
}
|
||||
}, schedule: { [weak textInputPanelNode] in
|
||||
}, schedule: { [weak textInputPanelNode] _ in
|
||||
textInputPanelNode?.sendMessage(.schedule)
|
||||
})
|
||||
controller.emojiViewProvider = textInputPanelNode.emojiViewProvider
|
||||
strongSelf.presentInGlobalOverlay(controller, nil)
|
||||
}, openScheduledMessages: {
|
||||
}, openPeersNearby: {
|
||||
|
@ -550,7 +550,7 @@ final class BusinessLinksSetupScreenComponent: Component {
|
||||
textColor: .primary,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -563,7 +563,7 @@ final class BusinessLinksSetupScreenComponent: Component {
|
||||
textColor: .destructive,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -2008,7 +2008,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
text: presentationData.strings.StorageManagement_PeerShowDetails,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2026,7 +2026,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
}
|
||||
},
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self, let component = self.component, let controller = self.controller?() else {
|
||||
return
|
||||
}
|
||||
@ -2049,7 +2049,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
text: presentationData.strings.StorageManagement_ContextSelect,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
})
|
||||
|
||||
guard let self, let aggregatedData = self.aggregatedData else {
|
||||
@ -2544,7 +2544,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
text: openTitle,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Expand"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2554,7 +2554,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self, let component = self.component, let controller = self.controller?(), let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
@ -2580,7 +2580,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuSelect, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
})
|
||||
|
||||
guard let self, let aggregatedData = self.aggregatedData else {
|
||||
@ -2641,7 +2641,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
text: openTitle,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Expand"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -2657,7 +2657,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor)
|
||||
},
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self, let component = self.component, let controller = self.controller?(), let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
@ -2684,7 +2684,7 @@ final class StorageUsageScreenComponent: Component {
|
||||
text: aggregatedData.selectionState.selectedMessages.contains(messageId) ? presentationData.strings.StorageManagement_ContextDeselect : presentationData.strings.StorageManagement_ContextSelect,
|
||||
icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) },
|
||||
action: { [weak self] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
})
|
||||
|
||||
guard let self, let aggregatedData = self.aggregatedData else {
|
||||
|
@ -6169,7 +6169,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
|
||||
items.append(.custom(SliderContextItem(minValue: 0.2, maxValue: 2.5, value: baseRate, valueChanged: { [weak self] newValue, done in
|
||||
@ -6260,11 +6260,11 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return optionsRateImage(rate: speedIconText, isLarge: false, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
guard let self else {
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
c.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
c?.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
@ -6476,11 +6476,11 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return optionsRateImage(rate: speedIconText, isLarge: false, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
guard let self else {
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
c.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
c?.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
@ -6791,11 +6791,11 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
return optionsRateImage(rate: speedIconText, isLarge: false, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
guard let self else {
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
c.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
c?.pushItems(items: self.contextMenuSpeedItems(value: baseRatePromise) |> map { ContextController.Items(content: .list($0)) })
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
|
@ -241,6 +241,19 @@ public final class AccountContextImpl: AccountContext {
|
||||
return availableReactionsValue.get()
|
||||
}
|
||||
|
||||
private var availableMessageEffectsValue: Promise<AvailableMessageEffects?>?
|
||||
public var availableMessageEffects: Signal<AvailableMessageEffects?, NoError> {
|
||||
let availableMessageEffectsValue: Promise<AvailableMessageEffects?>
|
||||
if let current = self.availableMessageEffectsValue {
|
||||
availableMessageEffectsValue = current
|
||||
} else {
|
||||
availableMessageEffectsValue = Promise<AvailableMessageEffects?>()
|
||||
self.availableMessageEffectsValue = availableMessageEffectsValue
|
||||
availableMessageEffectsValue.set(self.engine.stickers.availableMessageEffects())
|
||||
}
|
||||
return availableMessageEffectsValue.get()
|
||||
}
|
||||
|
||||
private var userLimitsConfigurationDisposable: Disposable?
|
||||
public private(set) var userLimits: EngineConfiguration.UserLimits
|
||||
|
||||
|
@ -3055,13 +3055,13 @@ extension ChatControllerImpl {
|
||||
} else {
|
||||
var contextItems: [ContextMenuItem] = []
|
||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(EnginePeer(peer).compactDisplayTitle).string, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pinAction(true, false)
|
||||
})
|
||||
})))
|
||||
|
||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesForMe, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pinAction(true, true)
|
||||
})
|
||||
})))
|
||||
@ -3074,13 +3074,13 @@ extension ChatControllerImpl {
|
||||
var contextItems: [ContextMenuItem] = []
|
||||
|
||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessageAlert_PinAndNotifyMembers, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pinAction(true, false)
|
||||
})
|
||||
})))
|
||||
|
||||
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessageAlert_OnlyPin, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
pinAction(false, false)
|
||||
})
|
||||
})))
|
||||
|
@ -476,7 +476,7 @@ extension ChatControllerImpl {
|
||||
self.updateDownButtonVisibility()
|
||||
}
|
||||
|
||||
func sendMediaRecording(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, viewOnce: Bool = false) {
|
||||
func sendMediaRecording(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, viewOnce: Bool = false, messageEffect: ChatSendMessageEffect? = nil) {
|
||||
self.chatDisplayNode.updateRecordedMediaDeleted(false)
|
||||
|
||||
guard let recordedMediaPreview = self.presentationInterfaceState.interfaceState.mediaDraftState else {
|
||||
|
@ -354,7 +354,7 @@ private func generateChatReplyOptionItems(selfController: ChatControllerImpl, ch
|
||||
subItems.append(.action(ContextMenuActionItem(text: selfController.presentationData.strings.Common_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
@ -379,7 +379,7 @@ private func generateChatReplyOptionItems(selfController: ChatControllerImpl, ch
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems), dismissed: { [weak contentNode] in
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems), dismissed: { [weak contentNode] in
|
||||
guard let contentNode else {
|
||||
return
|
||||
}
|
||||
|
@ -11,6 +11,13 @@ import ChatSendMessageActionUI
|
||||
import AccountContext
|
||||
import TopMessageReactions
|
||||
import ReactionSelectionNode
|
||||
import ChatControllerInteraction
|
||||
|
||||
extension ChatSendMessageEffect {
|
||||
convenience init(_ effect: ChatSendMessageActionSheetController.MessageEffect) {
|
||||
self.init(id: effect.id)
|
||||
}
|
||||
}
|
||||
|
||||
func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, node: ASDisplayNode, gesture: ContextGesture) {
|
||||
guard let peerId = selfController.chatLocation.peerId, let textInputView = selfController.chatDisplayNode.textInputView(), let layout = selfController.validLayout else {
|
||||
@ -61,22 +68,22 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
|
||||
let _ = ApplicationSpecificNotice.incrementSendWhenOnlineTip(accountManager: selfController.context.sharedContext.accountManager, count: 4).startStandalone()
|
||||
}
|
||||
|
||||
let controller = ChatSendMessageActionSheetController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, peerId: selfController.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputView, canSendWhenOnline: sendWhenOnlineAvailable, completion: { [weak selfController] in
|
||||
let controller = makeChatSendMessageActionSheetController(context: selfController.context, updatedPresentationData: selfController.updatedPresentationData, peerId: selfController.presentationInterfaceState.chatLocation.peerId, forwardMessageIds: selfController.presentationInterfaceState.interfaceState.forwardMessageIds, hasEntityKeyboard: hasEntityKeyboard, gesture: gesture, sourceSendButton: node, textInputView: textInputView, emojiViewProvider: selfController.chatDisplayNode.textInputPanelNode?.emojiViewProvider, wallpaperBackgroundNode: selfController.chatDisplayNode.backgroundNode, canSendWhenOnline: sendWhenOnlineAvailable, completion: { [weak selfController] in
|
||||
guard let selfController else {
|
||||
return
|
||||
}
|
||||
selfController.supportedOrientations = previousSupportedOrientations
|
||||
}, sendMessage: { [weak selfController] mode in
|
||||
}, sendMessage: { [weak selfController] mode, messageEffect in
|
||||
guard let selfController else {
|
||||
return
|
||||
}
|
||||
switch mode {
|
||||
case .generic:
|
||||
selfController.controllerInteraction?.sendCurrentMessage(false)
|
||||
selfController.controllerInteraction?.sendCurrentMessage(false, messageEffect.flatMap(ChatSendMessageEffect.init))
|
||||
case .silently:
|
||||
selfController.controllerInteraction?.sendCurrentMessage(true)
|
||||
selfController.controllerInteraction?.sendCurrentMessage(true, messageEffect.flatMap(ChatSendMessageEffect.init))
|
||||
case .whenOnline:
|
||||
selfController.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleWhenOnlineTimestamp) { [weak selfController] in
|
||||
selfController.chatDisplayNode.sendCurrentMessage(scheduleTime: scheduleWhenOnlineTimestamp, messageEffect: messageEffect.flatMap(ChatSendMessageEffect.init)) { [weak selfController] in
|
||||
guard let selfController else {
|
||||
return
|
||||
}
|
||||
@ -86,13 +93,12 @@ func chatMessageDisplaySendMessageOptions(selfController: ChatControllerImpl, no
|
||||
selfController.openScheduledMessages()
|
||||
}
|
||||
}
|
||||
}, schedule: { [weak selfController] in
|
||||
}, schedule: { [weak selfController] messageEffect in
|
||||
guard let selfController else {
|
||||
return
|
||||
}
|
||||
selfController.controllerInteraction?.scheduleCurrentMessage()
|
||||
}, reactionItems: effectItems)
|
||||
controller.emojiViewProvider = selfController.chatDisplayNode.textInputPanelNode?.emojiViewProvider
|
||||
selfController.sendMessageActionsController = controller
|
||||
if layout.isNonExclusive {
|
||||
selfController.present(controller, in: .window(.root))
|
||||
|
@ -1731,12 +1731,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.announcement, argument: text as NSString)
|
||||
})
|
||||
}
|
||||
}, sendCurrentMessage: { [weak self] silentPosting in
|
||||
}, sendCurrentMessage: { [weak self] silentPosting, messageEffect in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
||||
strongSelf.sendMediaRecording(silentPosting: silentPosting)
|
||||
strongSelf.sendMediaRecording(silentPosting: silentPosting, messageEffect: messageEffect)
|
||||
} else {
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting)
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, messageEffect: messageEffect)
|
||||
}
|
||||
}
|
||||
}, sendMessage: { [weak self] text in
|
||||
@ -3306,10 +3306,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
|
||||
strongSelf.sendMediaRecording(scheduleTime: time)
|
||||
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: nil)
|
||||
} else {
|
||||
let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time) { [weak self] in
|
||||
strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, messageEffect: nil) { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, {
|
||||
$0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) }
|
||||
|
@ -488,7 +488,7 @@ extension ChatControllerImpl {
|
||||
f(.dismissWithoutContent)
|
||||
commit()
|
||||
} else {
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
|
||||
commit()
|
||||
})
|
||||
@ -541,7 +541,7 @@ extension ChatControllerImpl {
|
||||
f(.dismissWithoutContent)
|
||||
commit()
|
||||
} else {
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: {
|
||||
commit()
|
||||
})
|
||||
|
@ -3821,7 +3821,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
func sendCurrentMessage(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, completion: @escaping () -> Void = {}) {
|
||||
func sendCurrentMessage(silentPosting: Bool? = nil, scheduleTime: Int32? = nil, messageEffect: ChatSendMessageEffect? = nil, completion: @escaping () -> Void = {}) {
|
||||
if let textInputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode {
|
||||
self.historyNode.justSentTextMessage = true
|
||||
|
||||
@ -4031,6 +4031,14 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
if !messages.isEmpty, let messageEffect {
|
||||
messages[0] = messages[0].withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
attributes.append(EffectMessageAttribute(id: messageEffect.id))
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
|
||||
if !messages.isEmpty || postEmptyMessages || self.chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil {
|
||||
if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
|
||||
var attributes: [MessageAttribute] = []
|
||||
|
@ -85,7 +85,7 @@ extension ChatControllerImpl {
|
||||
a(.default)
|
||||
return
|
||||
}
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
@ -334,6 +334,7 @@ private func extractAssociatedData(
|
||||
currentlyPlayingMessageId: MessageIndex?,
|
||||
isCopyProtectionEnabled: Bool,
|
||||
availableReactions: AvailableReactions?,
|
||||
availableMessageEffects: AvailableMessageEffects?,
|
||||
savedMessageTags: SavedMessageTags?,
|
||||
defaultReaction: MessageReaction.Reaction?,
|
||||
isPremium: Bool,
|
||||
@ -402,7 +403,7 @@ private func extractAssociatedData(
|
||||
automaticDownloadPeerId = message.peerId
|
||||
}
|
||||
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadPeerId: automaticDownloadPeerId, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, topicAuthorId: topicAuthorId, hasBots: hasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: isInline)
|
||||
return ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadPeerId: automaticDownloadPeerId, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, subject: subject, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, accountPeer: accountPeer, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, topicAuthorId: topicAuthorId, hasBots: hasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: isInline)
|
||||
}
|
||||
|
||||
private extension ChatHistoryLocationInput {
|
||||
@ -1459,6 +1460,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
}
|
||||
|
||||
let availableReactions: Signal<AvailableReactions?, NoError> = (context as! AccountContextImpl).availableReactions
|
||||
let availableMessageEffects: Signal<AvailableMessageEffects?, NoError> = (context as! AccountContextImpl).availableMessageEffects
|
||||
|
||||
let savedMessageTags: Signal<SavedMessageTags?, NoError>
|
||||
if chatLocation.peerId == self.context.account.peerId {
|
||||
savedMessageTags = context.engine.stickers.savedMessageTagData()
|
||||
@ -1570,6 +1573,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
customChannelDiscussionReadState,
|
||||
customThreadOutgoingReadState,
|
||||
availableReactions,
|
||||
availableMessageEffects,
|
||||
savedMessageTags,
|
||||
defaultReaction,
|
||||
accountPeer,
|
||||
@ -1582,7 +1586,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
audioTranscriptionTrial,
|
||||
chatThemes,
|
||||
deviceContactsNumbers
|
||||
).startStrict(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, availableReactions, savedMessageTags, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId, translationState, maxReadStoryId, recommendedChannels, audioTranscriptionTrial, chatThemes, deviceContactsNumbers in
|
||||
).startStrict(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, availableReactions, availableMessageEffects, savedMessageTags, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId, translationState, maxReadStoryId, recommendedChannels, audioTranscriptionTrial, chatThemes, deviceContactsNumbers in
|
||||
let (historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, currentlyPlayingMessageIdAndType, scrollToMessageId, chatHasBots, allAdMessages) = promises
|
||||
|
||||
func applyHole() {
|
||||
@ -1801,7 +1805,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
translateToLanguage = languageCode
|
||||
}
|
||||
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated)
|
||||
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated)
|
||||
|
||||
var includeEmbeddedSavedChatInfo = false
|
||||
if case let .replyThread(message) = chatLocation, message.peerId == context.account.peerId, !rotated {
|
||||
@ -3528,12 +3532,18 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
|
||||
if let currentRange = strongSelf.controllerInteraction.unreadMessageRange[rangeKey] {
|
||||
if currentRange.upperBound < (updatedIncomingId + 1) {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[UnreadMessageRangeKey(peerId: peerId, namespace: namespace)] = currentRange.lowerBound ..< (updatedIncomingId + 1)
|
||||
unreadMessageRangeUpdated = true
|
||||
let updatedRange = currentRange.lowerBound ..< (updatedIncomingId + 1)
|
||||
if strongSelf.controllerInteraction.unreadMessageRange[rangeKey] != updatedRange {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[rangeKey] = updatedRange
|
||||
unreadMessageRangeUpdated = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[rangeKey] = (previousIncomingId + 1) ..< (updatedIncomingId + 1)
|
||||
unreadMessageRangeUpdated = true
|
||||
let updatedRange = (previousIncomingId + 1) ..< (updatedIncomingId + 1)
|
||||
if strongSelf.controllerInteraction.unreadMessageRange[rangeKey] != updatedRange {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[rangeKey] = updatedRange
|
||||
unreadMessageRangeUpdated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
case .indexBased:
|
||||
@ -3547,6 +3557,33 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
//print("Read from \(previousPeerReadState) up to \(updatedPeerReadState)")
|
||||
}
|
||||
}
|
||||
} else if case let .peer(peerId) = strongSelf.chatLocation, case let .peer(updatedReadStates) = transition.historyView.originalView.transientReadStates {
|
||||
if let updatedPeerReadState = updatedReadStates[peerId] {
|
||||
for (namespace, updatedState) in updatedPeerReadState.states {
|
||||
switch updatedState {
|
||||
case let .idBased(updatedIncomingId, _, _, _, _):
|
||||
let rangeKey = UnreadMessageRangeKey(peerId: peerId, namespace: namespace)
|
||||
|
||||
if let currentRange = strongSelf.controllerInteraction.unreadMessageRange[rangeKey] {
|
||||
if currentRange.upperBound < (updatedIncomingId + 1) {
|
||||
let updatedRange = currentRange.lowerBound ..< (updatedIncomingId + 1)
|
||||
if strongSelf.controllerInteraction.unreadMessageRange[rangeKey] != updatedRange {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[rangeKey] = updatedRange
|
||||
unreadMessageRangeUpdated = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let updatedRange = (updatedIncomingId + 1) ..< (Int32.max - 1)
|
||||
if strongSelf.controllerInteraction.unreadMessageRange[rangeKey] != updatedRange {
|
||||
strongSelf.controllerInteraction.unreadMessageRange[rangeKey] = updatedRange
|
||||
unreadMessageRangeUpdated = true
|
||||
}
|
||||
}
|
||||
case .indexBased:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.historyView = transition.historyView
|
||||
|
@ -494,7 +494,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
subItems.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, textColor: .primary, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, iconPosition: .left, action: { c, _ in
|
||||
c.popItems()
|
||||
c?.popItems()
|
||||
})))
|
||||
|
||||
subItems.append(.separator)
|
||||
@ -503,7 +503,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
subItems.append(.action(ContextMenuActionItem(text: sponsorInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = sponsorInfo
|
||||
|
||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
||||
@ -515,7 +515,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
subItems.append(.action(ContextMenuActionItem(text: additionalInfo, textColor: .primary, textLayout: .multiline, textFont: .custom(font: Font.regular(floor(presentationData.listsFontSize.baseDisplaySize * 0.8)), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return nil
|
||||
}, iconSource: nil, action: { [weak controllerInteraction] c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
UIPasteboard.general.string = additionalInfo
|
||||
|
||||
let content: UndoOverlayContent = .copy(text: presentationData.strings.Chat_ContextMenu_AdSponsorInfoCopied)
|
||||
@ -524,7 +524,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
})))
|
||||
}
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
actions.append(.separator)
|
||||
}
|
||||
@ -572,7 +572,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.Chat_ContextMenu_RemoveAd, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
controllerInteraction.openNoAdsDemo()
|
||||
})
|
||||
})))
|
||||
@ -589,7 +589,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Hide, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(font: Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0), height: nil, verticalOffset: nil), badge: nil, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.primaryTextColor)
|
||||
}, iconSource: nil, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .noAds, forceDark: false, action: {
|
||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .ads, forceDark: false, dismissed: nil)
|
||||
@ -1112,7 +1112,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reply"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
interfaceInteraction.setupReplyMessage(messages[0].id, { transition, completed in
|
||||
c.dismiss(result: .custom(transition), completion: {
|
||||
c?.dismiss(result: .custom(transition), completion: {
|
||||
completed()
|
||||
})
|
||||
})
|
||||
@ -1401,7 +1401,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.append(.action(ContextMenuActionItem(text: text, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replies"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
controllerInteraction.openMessageReplies(messages[0].id, true, true)
|
||||
})
|
||||
})))
|
||||
@ -1687,7 +1687,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextViewStats, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
controllerInteraction.openMessageStats(messages[0].id)
|
||||
})
|
||||
})))
|
||||
@ -1700,7 +1700,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ViewInChannel, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
c?.dismiss(completion: {
|
||||
guard let navigationController = controllerInteraction.navigationController() else {
|
||||
return
|
||||
}
|
||||
|
@ -680,7 +680,7 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, Chat
|
||||
return
|
||||
}
|
||||
|
||||
c.dismiss(completion: { [weak self] in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self, let item = self.items.first(where: { $0.reaction == reaction }) else {
|
||||
return
|
||||
}
|
||||
|
@ -298,7 +298,7 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
c.pushItems(items: .single(ContextController.Items(
|
||||
c?.pushItems(items: .single(ContextController.Items(
|
||||
content: .custom(
|
||||
TranslationLanguagesContextMenuContent(
|
||||
context: self.context,
|
||||
@ -322,7 +322,7 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
items.append(.action(ContextMenuActionItem(text: doNotTranslateTitle, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
|
||||
self?.interfaceInteraction?.addDoNotTranslateLanguage(translationState.fromLang)
|
||||
})))
|
||||
@ -330,7 +330,7 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_Translation_Hide, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] c, _ in
|
||||
c.dismiss(completion: nil)
|
||||
c?.dismiss(completion: nil)
|
||||
|
||||
self?.interfaceInteraction?.hideTranslationPanel()
|
||||
})))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user