[WIP] Quotes

This commit is contained in:
Ali 2023-10-09 20:24:17 +04:00
parent afcc8f39f2
commit f1a9bec56d
31 changed files with 784 additions and 645 deletions

View File

@ -10102,3 +10102,5 @@ Sorry for the inconvenience.";
"GiftLink.LinkSharedToChat" = "Gift link forwarded to **%@**";
"GiftLink.LinkSharedToSavedMessages" = "Gift link forwarded to **Saved Messages**";
"ChatContextMenu.TextSelectionTip2" = "Hold on a word, then move cursor to select more| text to copy or quote.";

View File

@ -528,10 +528,23 @@ public enum ChatControllerSubject: Equatable {
}
}
public struct MessageOptionsInfo: Equatable {
public enum Kind {
case forward
case reply
}
public let kind: Kind
public init(kind: Kind) {
self.kind = kind
}
}
case message(id: MessageSubject, highlight: Bool, timecode: Double?)
case scheduledMessages
case pinnedMessages(id: EngineMessage.Id?)
case forwardedMessages(peerIds: [EnginePeer.Id], ids: [EngineMessage.Id], options: Signal<ForwardOptions, NoError>)
case messageOptions(peerIds: [EnginePeer.Id], ids: [EngineMessage.Id], info: MessageOptionsInfo, options: Signal<ForwardOptions, NoError>)
public static func ==(lhs: ChatControllerSubject, rhs: ChatControllerSubject) -> Bool {
switch lhs {
@ -553,8 +566,8 @@ public enum ChatControllerSubject: Equatable {
} else {
return false
}
case let .forwardedMessages(lhsPeerIds, lhsIds, _):
if case let .forwardedMessages(rhsPeerIds, rhsIds, _) = rhs, lhsPeerIds == rhsPeerIds, lhsIds == rhsIds {
case let .messageOptions(lhsPeerIds, lhsIds, lhsInfo, _):
if case let .messageOptions(rhsPeerIds, rhsIds, rhsInfo, _) = rhs, lhsPeerIds == rhsPeerIds, lhsIds == rhsIds, lhsInfo == rhsInfo {
return true
} else {
return false

View File

@ -778,6 +778,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState($0.forwardOptionsState) }) })
}
}, presentForwardOptions: { _ in
}, presentReplyOptions: { _ in
}, shareSelectedMessages: {
}, updateTextInputStateAndMode: { [weak self] f in
if let strongSelf = self {

View File

@ -80,6 +80,7 @@ public final class ChatPanelInterfaceInteraction {
public let forwardMessages: ([Message]) -> Void
public let updateForwardOptionsState: ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void
public let presentForwardOptions: (ASDisplayNode) -> Void
public let presentReplyOptions: (ASDisplayNode) -> Void
public let shareSelectedMessages: () -> Void
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
@ -184,6 +185,7 @@ public final class ChatPanelInterfaceInteraction {
forwardMessages: @escaping ([Message]) -> Void,
updateForwardOptionsState: @escaping ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void,
presentForwardOptions: @escaping (ASDisplayNode) -> Void,
presentReplyOptions: @escaping (ASDisplayNode) -> Void,
shareSelectedMessages: @escaping () -> Void,
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
@ -287,6 +289,7 @@ public final class ChatPanelInterfaceInteraction {
self.forwardMessages = forwardMessages
self.updateForwardOptionsState = updateForwardOptionsState
self.presentForwardOptions = presentForwardOptions
self.presentReplyOptions = presentReplyOptions
self.shareSelectedMessages = shareSelectedMessages
self.updateTextInputStateAndMode = updateTextInputStateAndMode
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId
@ -398,6 +401,7 @@ public final class ChatPanelInterfaceInteraction {
}, forwardMessages: { _ in
}, updateForwardOptionsState: { _ in
}, presentForwardOptions: { _ in
}, presentReplyOptions: { _ in
}, shareSelectedMessages: {
}, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: {
}, editMessage: {

View File

@ -393,7 +393,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
var icon: UIImage?
switch tip {
case .textSelection:
var rawText = self.presentationData.strings.ChatContextMenu_TextSelectionTip
var rawText = self.presentationData.strings.ChatContextMenu_TextSelectionTip2
if let range = rawText.range(of: "|") {
rawText.removeSubrange(range)
self.text = rawText

View File

@ -181,6 +181,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case storyStealthModeReplyCount = 47
case viewOnceTooltip = 48
case displayStoryUnmuteTooltip = 49
case chatReplyOptionsTip = 50
var key: ValueBoxKey {
let v = ValueBoxKey(length: 4)
@ -355,6 +356,10 @@ private struct ApplicationSpecificNoticeKeys {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key)
}
static func chatReplyOptionsTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatReplyOptionsTip.key)
}
static func interactiveEmojiSyncTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.interactiveEmojiSyncTip.key)
}
@ -1245,6 +1250,33 @@ public struct ApplicationSpecificNotice {
}
}
public static func getChatReplyOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatReplyOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {
return value.value
} else {
return 0
}
}
}
public static func incrementChatReplyOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatReplyOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {
currentValue = value.value
}
let previousValue = currentValue
currentValue += Int32(count)
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
transaction.setNotice(ApplicationSpecificNoticeKeys.chatReplyOptionsTip(), entry)
}
return Int(previousValue)
}
}
public static func getClearStorageDismissedTipSize(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
return accountManager.transaction { transaction -> Int32 in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.clearStorageDismissedTipSize())?.get(ApplicationSpecificCounterNotice.self) {

View File

@ -87,7 +87,7 @@ public func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Mess
}
}
if let subject = associatedData.subject, case .forwardedMessages = subject {
if let subject = associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
authorTitle = nil
}

View File

@ -140,7 +140,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
let message = item.message
let incoming: Bool
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
} else {
incoming = item.message.effectivelyIncoming(item.context.account.peerId)
@ -181,7 +181,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
}
let dateFormat: MessageTimestampStatusFormat
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
dateFormat = .minimal
} else {
dateFormat = .regular
@ -344,7 +344,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
let textFont = item.presentationData.messageFont
if let entities = entities {
attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: messageTheme.accentControlColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, message: item.message, adjustQuoteFontSize: true)
attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: messageTheme.accentTextColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, message: item.message, adjustQuoteFontSize: true)
} else if !rawText.isEmpty {
attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor)
} else {
@ -563,6 +563,10 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
} else {
strongSelf.statusNode.pressed = nil
}
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .reply = info.kind {
strongSelf.updateIsExtractedToContextPreview(true)
}
}
})
})

View File

@ -369,7 +369,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
let chatController = strongSelf.context.sharedContext.makeChatController(
context: strongSelf.context,
chatLocation: .peer(id: strongSelf.context.account.peerId),
subject: .forwardedMessages(peerIds: peerIds, ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions),
subject: .messageOptions(peerIds: peerIds, ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], info: ChatControllerSubject.MessageOptionsInfo(kind: .forward), options: forwardOptions),
botStart: nil,
mode: .standard(previewing: true)
)
@ -543,6 +543,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
contextController.immediateItemsTransitionAnimation = true
strongSelf.controller?.presentInGlobalOverlay(contextController)
}, presentReplyOptions: { _ in
}, shareSelectedMessages: {
}, updateTextInputStateAndMode: { [weak self] f in
if let strongSelf = self {

View File

@ -0,0 +1,279 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import AccountContext
import ChatPresentationInterfaceState
import ContextUI
func presentChatForwardOptions(selfController: ChatControllerImpl, sourceNode: ASDisplayNode) {
guard let peerId = selfController.chatLocation.peerId else {
return
}
let presentationData = selfController.presentationData
let forwardOptions = selfController.presentationInterfaceStatePromise.get()
|> map { state -> ChatControllerSubject.ForwardOptions in
var hideNames = state.interfaceState.forwardOptionsState?.hideNames ?? false
if peerId.namespace == Namespaces.Peer.SecretChat {
hideNames = true
}
return ChatControllerSubject.ForwardOptions(hideNames: hideNames, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false)
}
|> distinctUntilChanged
let chatController = selfController.context.sharedContext.makeChatController(context: selfController.context, chatLocation: .peer(id: peerId), subject: .messageOptions(peerIds: [peerId], ids: selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], info: ChatControllerSubject.MessageOptionsInfo(kind: .forward), options: forwardOptions), botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
let messageIds = selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? []
let messagesCount: Signal<Int, NoError>
if let chatController = chatController as? ChatControllerImpl, messageIds.count > 1 {
messagesCount = .single(messageIds.count)
|> then(
chatController.presentationInterfaceStatePromise.get()
|> map { state -> Int in
return state.interfaceState.selectionState?.selectedIds.count ?? 1
}
)
} else {
messagesCount = .single(1)
}
let accountPeerId = selfController.context.account.peerId
let items = combineLatest(forwardOptions, selfController.context.account.postbox.messagesAtIds(messageIds), messagesCount)
|> deliverOnMainQueue
|> map { [weak selfController] forwardOptions, messages, messagesCount -> [ContextMenuItem] in
guard let selfController else {
return []
}
var items: [ContextMenuItem] = []
var hasCaptions = false
var uniquePeerIds = Set<PeerId>()
var hasOther = false
var hasNotOwnMessages = false
for message in messages {
if let author = message.effectiveAuthor {
if !uniquePeerIds.contains(author.id) {
uniquePeerIds.insert(author.id)
}
if message.id.peerId == accountPeerId && message.forwardInfo == nil {
} else {
hasNotOwnMessages = true
}
}
var isDice = false
var isMusic = false
for media in message.media {
if let media = media as? TelegramMediaFile, media.isMusic {
isMusic = true
} else if media is TelegramMediaDice {
isDice = true
} else {
if !message.text.isEmpty {
if media is TelegramMediaImage || media is TelegramMediaFile {
hasCaptions = true
}
}
}
}
if !isDice && !isMusic {
hasOther = true
}
}
var canHideNames = hasNotOwnMessages && hasOther
if case let .peer(peerId) = selfController.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
canHideNames = false
}
let hideNames = forwardOptions.hideNames
let hideCaptions = forwardOptions.hideCaptions
if canHideNames {
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in
if hideNames {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak selfController] _, f in
selfController?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = false
updated.hideCaptions = false
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in
if hideNames {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { [weak selfController] _, f in
selfController?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideNames = true
updated.unhideNamesOnCaptionChange = false
return updated
})
})))
items.append(.separator)
}
if hasCaptions {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in
if hideCaptions {
return nil
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
}
}, action: { [weak selfController] _, f in
selfController?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = false
if canHideNames {
if updated.unhideNamesOnCaptionChange {
updated.unhideNamesOnCaptionChange = false
updated.hideNames = false
}
}
return updated
})
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in
if hideCaptions {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { [weak selfController] _, f in
selfController?.interfaceInteraction?.updateForwardOptionsState({ current in
var updated = current
updated.hideCaptions = true
if canHideNames {
if !updated.hideNames {
updated.hideNames = true
updated.unhideNamesOnCaptionChange = true
}
}
return updated
})
})))
items.append(.separator)
}
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ChangeRecipient, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak selfController] c, f in
selfController?.interfaceInteraction?.forwardCurrentForwardMessages()
f(.default)
})))
items.append(.action(ContextMenuActionItem(text: messagesCount == 1 ? presentationData.strings.Conversation_ForwardOptions_SendMessage : presentationData.strings.Conversation_ForwardOptions_SendMessages, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.contextMenu.primaryColor) }, action: { [weak selfController, weak chatController] c, f in
guard let selfController else {
return
}
if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds {
var forwardMessageIds = selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? []
forwardMessageIds = forwardMessageIds.filter { selectedMessageIds.contains($0) }
selfController.updateChatPresentationInterfaceState(interactive: false, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(forwardMessageIds) }) })
}
selfController.controllerInteraction?.sendCurrentMessage(false)
f(.default)
})))
return items
}
selfController.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
selfController.canReadHistory.set(false)
let contextController = ContextController(presentationData: selfController.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)), items: items |> map { ContextController.Items(content: .list($0)) })
contextController.dismissed = { [weak selfController] in
selfController?.canReadHistory.set(true)
}
contextController.dismissedForCancel = { [weak selfController, weak chatController] in
guard let selfController else {
return
}
if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds {
var forwardMessageIds = selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? []
forwardMessageIds = forwardMessageIds.filter { selectedMessageIds.contains($0) }
selfController.updateChatPresentationInterfaceState(interactive: false, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(forwardMessageIds) }) })
}
}
contextController.immediateItemsTransitionAnimation = true
selfController.presentInGlobalOverlay(contextController)
}
func presentChatReplyOptions(selfController: ChatControllerImpl, sourceNode: ASDisplayNode) {
guard let peerId = selfController.chatLocation.peerId else {
return
}
guard let replySubject = selfController.presentationInterfaceState.interfaceState.replyMessageSubject else {
return
}
//let presentationData = selfController.presentationData
let chatController = selfController.context.sharedContext.makeChatController(context: selfController.context, chatLocation: .peer(id: peerId), subject: .messageOptions(peerIds: [replySubject.messageId.peerId], ids: [replySubject.messageId], info: ChatControllerSubject.MessageOptionsInfo(kind: .reply), options: .single(ChatControllerSubject.ForwardOptions(hideNames: false, hideCaptions: false))), botStart: nil, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
let messageIds: [EngineMessage.Id] = [replySubject.messageId]
let messagesCount: Signal<Int, NoError> = .single(1)
//let accountPeerId = selfController.context.account.peerId
let items = combineLatest(selfController.context.account.postbox.messagesAtIds(messageIds), messagesCount)
|> deliverOnMainQueue
|> map { [weak selfController] messages, messagesCount -> [ContextMenuItem] in
guard let selfController else {
return []
}
var items: [ContextMenuItem] = []
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Reply in Another Chat", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak selfController] c, f in
selfController?.interfaceInteraction?.forwardCurrentForwardMessages()
f(.default)
})))
return items
}
selfController.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
selfController.canReadHistory.set(false)
let contextController = ContextController(presentationData: selfController.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)), items: items |> map { ContextController.Items(content: .list($0)) })
contextController.dismissed = { [weak selfController] in
selfController?.canReadHistory.set(true)
}
contextController.dismissedForCancel = { [weak selfController, weak chatController] in
guard let selfController else {
return
}
if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds {
var forwardMessageIds = selfController.presentationInterfaceState.interfaceState.forwardMessageIds ?? []
forwardMessageIds = forwardMessageIds.filter { selectedMessageIds.contains($0) }
selfController.updateChatPresentationInterfaceState(interactive: false, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(forwardMessageIds) }) })
}
}
contextController.immediateItemsTransitionAnimation = true
selfController.presentInGlobalOverlay(contextController)
}

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,7 @@ import ForwardAccessoryPanelNode
import ChatOverscrollControl
import ChatInputPanelNode
import ChatInputContextPanelNode
import TextSelectionNode
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
let itemNode: OverlayMediaItemNode
@ -392,7 +393,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
var source: ChatHistoryListSource
if case let .forwardedMessages(_, messageIds, options) = subject {
if case let .messageOptions(_, messageIds, info, options) = subject {
let messages = combineLatest(context.account.postbox.messagesAtIds(messageIds), context.account.postbox.loadedPeerWithId(context.account.peerId), options)
|> map { messages, accountPeer, options -> ([Message], Int32, Bool) in
var messages = messages
@ -412,28 +413,30 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var attributes = message.attributes
attributes = attributes.filter({ attribute in
if attribute is EditedMessageAttribute {
return false
}
if let attribute = attribute as? ReplyMessageAttribute {
if !forwardedMessageIds.contains(attribute.messageId) || hideNames {
if case .forward = info.kind {
if attribute is EditedMessageAttribute {
return false
}
if let attribute = attribute as? ReplyMessageAttribute {
if !forwardedMessageIds.contains(attribute.messageId) || hideNames {
return false
}
}
if attribute is ReplyMarkupMessageAttribute {
return false
}
if attribute is ReplyThreadMessageAttribute {
return false
}
if attribute is ViewCountMessageAttribute{
return false
}
if attribute is ForwardCountMessageAttribute {
return false
}
if attribute is ReactionsMessageAttribute {
return false
}
}
if attribute is ReplyMarkupMessageAttribute {
return false
}
if attribute is ReplyThreadMessageAttribute {
return false
}
if attribute is ViewCountMessageAttribute{
return false
}
if attribute is ForwardCountMessageAttribute {
return false
}
if attribute is ReactionsMessageAttribute {
return false
}
return true
})
@ -2965,6 +2968,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
switch self.chatPresentationInterfaceState.mode {
case .standard(previewing: true):
if let subject = self.controller?.subject, case let .messageOptions(_, _, info, _) = subject, case .reply = info.kind {
if let result = self.historyNode.view.hitTest(self.view.convert(point, to: self.historyNode.view), with: event), let node = result.asyncdisplaykit_node {
if node is TextSelectionNode {
return result
}
}
}
if let result = self.historyNode.view.hitTest(self.view.convert(point, to: self.historyNode.view), with: event), let node = result.asyncdisplaykit_node, node is ChatMessageSelectionNode || node is GridMessageSelectionNode {
return result
}

View File

@ -17,10 +17,10 @@ func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceS
}
switch chatPresentationInterfaceState.subject {
case .pinnedMessages, .forwardedMessages:
return nil
default:
break
case .pinnedMessages, .messageOptions:
return nil
default:
break
}
if let editMessage = chatPresentationInterfaceState.interfaceState.editMessage {

View File

@ -16,7 +16,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
return (nil, nil)
}
if case .forwardedMessages = chatPresentationInterfaceState.subject {
if case .messageOptions = chatPresentationInterfaceState.subject {
return (nil, nil)
}

View File

@ -29,7 +29,7 @@ struct ChatNavigationButton: Equatable {
func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, subject: ChatControllerSubject?, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?) -> ChatNavigationButton? {
if let _ = presentationInterfaceState.interfaceState.selectionState {
if case .forwardedMessages = presentationInterfaceState.subject {
if case .messageOptions = presentationInterfaceState.subject {
return nil
}
if let _ = presentationInterfaceState.reportReason {
@ -78,7 +78,7 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
if let _ = presentationInterfaceState.interfaceState.selectionState {
if case .forwardedMessages = presentationInterfaceState.subject {
if case .messageOptions = presentationInterfaceState.subject {
return nil
}
if let currentButton = currentButton, currentButton.action == .cancelMessageSelection {
@ -107,7 +107,7 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
}
}
if case .forwardedMessages = presentationInterfaceState.subject {
if case .messageOptions = presentationInterfaceState.subject {
return nil
}

View File

@ -18,7 +18,7 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
var inhibitTitlePanelDisplay = false
switch chatPresentationInterfaceState.subject {
case .forwardedMessages:
case .messageOptions:
return nil
case .scheduledMessages, .pinnedMessages:
inhibitTitlePanelDisplay = true

View File

@ -1065,7 +1065,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
needsShareButton = false
}
@ -1438,7 +1438,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
var transition: ContainedViewLayoutTransition = .immediate
if case let .System(duration, _) = animation {
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
transition = .animated(duration: duration, curve: .linear)
} else {
transition = .animated(duration: duration, curve: .spring)

View File

@ -378,7 +378,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
let textBlockQuoteFont = Font.regular(fontSize)
var incoming = message.effectivelyIncoming(context.account.peerId)
if case .forwardedMessages = associatedData.subject {
if let subject = associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -1122,6 +1122,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
self.replyRecognizer = replyRecognizer
self.view.addGestureRecognizer(replyRecognizer)
if let item = self.item, let subject = item.associatedData.subject, case .messageOptions = subject {
self.tapRecognizer?.isEnabled = false
self.replyRecognizer?.isEnabled = false
}
}
override func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
@ -1233,7 +1238,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
do {
let peerId = chatLocationPeerId
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
displayAuthorInfo = false
} else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
if let forwardInfo = item.content.firstMessage.forwardInfo {
@ -1412,7 +1417,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
}
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
needsShareButton = false
}
@ -1904,7 +1909,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
let dateFormat: MessageTimestampStatusFormat
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
dateFormat = .minimal
} else {
dateFormat = .regular
@ -2697,7 +2702,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
if case let .System(duration, _) = animation {
legacyTransition = .animated(duration: duration, curve: .spring)
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
useDisplayLinkAnimations = true
}
}
@ -3525,6 +3530,15 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
strongSelf.mainContextSourceNode.layoutUpdated?(strongSelf.mainContextSourceNode.bounds.size, animation)
}
if let subject = item.associatedData.subject, case .messageOptions = subject {
strongSelf.tapRecognizer?.isEnabled = false
strongSelf.replyRecognizer?.isEnabled = false
strongSelf.mainContainerNode.isGestureEnabled = false
for contentContainer in strongSelf.contentContainers {
contentContainer.containerNode.isGestureEnabled = false
}
}
strongSelf.updateSearchTextHighlightState()
if let (_, f) = strongSelf.awaitingAppliedReaction {
@ -3532,7 +3546,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
f()
}
}
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {

View File

@ -96,7 +96,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
}
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -106,7 +106,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
}
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}
let statusType: ChatMessageDateAndStatusType?

View File

@ -185,7 +185,7 @@ class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode {
}
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -176,7 +176,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
}
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -375,7 +375,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
}
}
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
needsShareButton = false
}

View File

@ -235,7 +235,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
var updatedMuteIconImage: UIImage?
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -18,7 +18,7 @@ public enum ChatMessageItemContent: Sequence {
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)])
func effectivelyIncoming(_ accountPeerId: PeerId, associatedData: ChatMessageItemAssociatedData? = nil) -> Bool {
if let subject = associatedData?.subject, case .forwardedMessages = subject {
if let subject = associatedData?.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
return false
}
switch self {
@ -420,7 +420,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
self.avatarHeader = avatarHeader
var headers: [ListViewItemHeader] = [self.dateHeader]
if case .forwardedMessages = associatedData.subject {
if case .messageOptions = associatedData.subject {
headers = []
}
if let avatarHeader = self.avatarHeader {

View File

@ -92,7 +92,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
}
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
if case .forwardedMessages = item.associatedData.subject {
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .forward = info.kind {
incoming = false
}

View File

@ -528,7 +528,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
}
}
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
if let subject = item.associatedData.subject, case .messageOptions = subject {
needsShareButton = false
}

View File

@ -73,6 +73,7 @@ final class ChatRecentActionsController: TelegramBaseController {
}, forwardMessages: { _ in
}, updateForwardOptionsState: { _ in
}, presentForwardOptions: { _ in
}, presentReplyOptions: { _ in
}, shareSelectedMessages: {
}, updateTextInputStateAndMode: { _ in
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in

View File

@ -310,6 +310,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
}, forwardMessages: { _ in
}, updateForwardOptionsState: { _ in
}, presentForwardOptions: { _ in
}, presentReplyOptions: { _ in
}, shareSelectedMessages: {
shareMessages()
}, updateTextInputStateAndMode: { _ in

View File

@ -17,6 +17,7 @@ import TextNodeWithEntities
import AnimationCache
import MultiAnimationRenderer
import AccessoryPanelNode
import TelegramNotices
final class ReplyAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable()
@ -286,7 +287,11 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
if self.theme !== theme {
self.updateThemeAndStrings(theme: theme, strings: strings, force: false)
}
private func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, force: Bool) {
if self.theme !== theme || force {
self.theme = theme
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
@ -362,9 +367,26 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
}
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
private var previousTapTimestamp: Double?
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
let timestamp = CFAbsoluteTimeGetCurrent()
if let previousTapTimestamp = self.previousTapTimestamp, previousTapTimestamp + 1.0 > timestamp {
return
}
self.previousTapTimestamp = CFAbsoluteTimeGetCurrent()
self.interfaceInteraction?.presentReplyOptions(self)
Queue.mainQueue().after(1.5) {
self.updateThemeAndStrings(theme: self.theme, strings: self.strings, force: true)
}
let _ = ApplicationSpecificNotice.incrementChatReplyOptionsTip(accountManager: self.context.sharedContext.accountManager, count: 3).start()
}
}
/*@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state {
self.interfaceInteraction?.navigateToMessage(self.messageId, false, true, .generic)
}
}
}*/
}