mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 21:16:35 +00:00
[WIP] Quotes
This commit is contained in:
parent
afcc8f39f2
commit
f1a9bec56d
@ -10102,3 +10102,5 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"GiftLink.LinkSharedToChat" = "Gift link forwarded to **%@**";
|
"GiftLink.LinkSharedToChat" = "Gift link forwarded to **%@**";
|
||||||
"GiftLink.LinkSharedToSavedMessages" = "Gift link forwarded to **Saved Messages**";
|
"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.";
|
||||||
|
|||||||
@ -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 message(id: MessageSubject, highlight: Bool, timecode: Double?)
|
||||||
case scheduledMessages
|
case scheduledMessages
|
||||||
case pinnedMessages(id: EngineMessage.Id?)
|
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 {
|
public static func ==(lhs: ChatControllerSubject, rhs: ChatControllerSubject) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
@ -553,8 +566,8 @@ public enum ChatControllerSubject: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .forwardedMessages(lhsPeerIds, lhsIds, _):
|
case let .messageOptions(lhsPeerIds, lhsIds, lhsInfo, _):
|
||||||
if case let .forwardedMessages(rhsPeerIds, rhsIds, _) = rhs, lhsPeerIds == rhsPeerIds, lhsIds == rhsIds {
|
if case let .messageOptions(rhsPeerIds, rhsIds, rhsInfo, _) = rhs, lhsPeerIds == rhsPeerIds, lhsIds == rhsIds, lhsInfo == rhsInfo {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -778,6 +778,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState($0.forwardOptionsState) }) })
|
strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState($0.forwardOptionsState) }) })
|
||||||
}
|
}
|
||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
|
}, presentReplyOptions: { _ in
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { [weak self] f in
|
}, updateTextInputStateAndMode: { [weak self] f in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
|||||||
@ -80,6 +80,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
public let forwardMessages: ([Message]) -> Void
|
public let forwardMessages: ([Message]) -> Void
|
||||||
public let updateForwardOptionsState: ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void
|
public let updateForwardOptionsState: ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void
|
||||||
public let presentForwardOptions: (ASDisplayNode) -> Void
|
public let presentForwardOptions: (ASDisplayNode) -> Void
|
||||||
|
public let presentReplyOptions: (ASDisplayNode) -> Void
|
||||||
public let shareSelectedMessages: () -> Void
|
public let shareSelectedMessages: () -> Void
|
||||||
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
|
public let updateTextInputStateAndMode: (@escaping (ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void
|
||||||
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
|
public let updateInputModeAndDismissedButtonKeyboardMessageId: ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void
|
||||||
@ -184,6 +185,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
forwardMessages: @escaping ([Message]) -> Void,
|
forwardMessages: @escaping ([Message]) -> Void,
|
||||||
updateForwardOptionsState: @escaping ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void,
|
updateForwardOptionsState: @escaping ((ChatInterfaceForwardOptionsState) -> ChatInterfaceForwardOptionsState) -> Void,
|
||||||
presentForwardOptions: @escaping (ASDisplayNode) -> Void,
|
presentForwardOptions: @escaping (ASDisplayNode) -> Void,
|
||||||
|
presentReplyOptions: @escaping (ASDisplayNode) -> Void,
|
||||||
shareSelectedMessages: @escaping () -> Void,
|
shareSelectedMessages: @escaping () -> Void,
|
||||||
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
updateTextInputStateAndMode: @escaping ((ChatTextInputState, ChatInputMode) -> (ChatTextInputState, ChatInputMode)) -> Void,
|
||||||
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
updateInputModeAndDismissedButtonKeyboardMessageId: @escaping ((ChatPresentationInterfaceState) -> (ChatInputMode, MessageId?)) -> Void,
|
||||||
@ -287,6 +289,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
self.forwardMessages = forwardMessages
|
self.forwardMessages = forwardMessages
|
||||||
self.updateForwardOptionsState = updateForwardOptionsState
|
self.updateForwardOptionsState = updateForwardOptionsState
|
||||||
self.presentForwardOptions = presentForwardOptions
|
self.presentForwardOptions = presentForwardOptions
|
||||||
|
self.presentReplyOptions = presentReplyOptions
|
||||||
self.shareSelectedMessages = shareSelectedMessages
|
self.shareSelectedMessages = shareSelectedMessages
|
||||||
self.updateTextInputStateAndMode = updateTextInputStateAndMode
|
self.updateTextInputStateAndMode = updateTextInputStateAndMode
|
||||||
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId
|
self.updateInputModeAndDismissedButtonKeyboardMessageId = updateInputModeAndDismissedButtonKeyboardMessageId
|
||||||
@ -398,6 +401,7 @@ public final class ChatPanelInterfaceInteraction {
|
|||||||
}, forwardMessages: { _ in
|
}, forwardMessages: { _ in
|
||||||
}, updateForwardOptionsState: { _ in
|
}, updateForwardOptionsState: { _ in
|
||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
|
}, presentReplyOptions: { _ in
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: {
|
}, updateTextInputStateAndMode: updateTextInputStateAndMode, updateInputModeAndDismissedButtonKeyboardMessageId: updateInputModeAndDismissedButtonKeyboardMessageId, openStickers: {
|
||||||
}, editMessage: {
|
}, editMessage: {
|
||||||
|
|||||||
@ -393,7 +393,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
|
|||||||
var icon: UIImage?
|
var icon: UIImage?
|
||||||
switch tip {
|
switch tip {
|
||||||
case .textSelection:
|
case .textSelection:
|
||||||
var rawText = self.presentationData.strings.ChatContextMenu_TextSelectionTip
|
var rawText = self.presentationData.strings.ChatContextMenu_TextSelectionTip2
|
||||||
if let range = rawText.range(of: "|") {
|
if let range = rawText.range(of: "|") {
|
||||||
rawText.removeSubrange(range)
|
rawText.removeSubrange(range)
|
||||||
self.text = rawText
|
self.text = rawText
|
||||||
|
|||||||
@ -181,6 +181,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
|||||||
case storyStealthModeReplyCount = 47
|
case storyStealthModeReplyCount = 47
|
||||||
case viewOnceTooltip = 48
|
case viewOnceTooltip = 48
|
||||||
case displayStoryUnmuteTooltip = 49
|
case displayStoryUnmuteTooltip = 49
|
||||||
|
case chatReplyOptionsTip = 50
|
||||||
|
|
||||||
var key: ValueBoxKey {
|
var key: ValueBoxKey {
|
||||||
let v = ValueBoxKey(length: 4)
|
let v = ValueBoxKey(length: 4)
|
||||||
@ -355,6 +356,10 @@ private struct ApplicationSpecificNoticeKeys {
|
|||||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatForwardOptionsTip.key)
|
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 {
|
static func interactiveEmojiSyncTip() -> NoticeEntryKey {
|
||||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.interactiveEmojiSyncTip.key)
|
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> {
|
public static func getClearStorageDismissedTipSize(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||||
return accountManager.transaction { transaction -> Int32 in
|
return accountManager.transaction { transaction -> Int32 in
|
||||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.clearStorageDismissedTipSize())?.get(ApplicationSpecificCounterNotice.self) {
|
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.clearStorageDismissedTipSize())?.get(ApplicationSpecificCounterNotice.self) {
|
||||||
|
|||||||
@ -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
|
authorTitle = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -140,7 +140,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let message = item.message
|
let message = item.message
|
||||||
|
|
||||||
let incoming: Bool
|
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
|
incoming = false
|
||||||
} else {
|
} else {
|
||||||
incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||||
@ -181,7 +181,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dateFormat: MessageTimestampStatusFormat
|
let dateFormat: MessageTimestampStatusFormat
|
||||||
if let subject = item.associatedData.subject, case .forwardedMessages = subject {
|
if let subject = item.associatedData.subject, case .messageOptions = subject {
|
||||||
dateFormat = .minimal
|
dateFormat = .minimal
|
||||||
} else {
|
} else {
|
||||||
dateFormat = .regular
|
dateFormat = .regular
|
||||||
@ -344,7 +344,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let textFont = item.presentationData.messageFont
|
let textFont = item.presentationData.messageFont
|
||||||
|
|
||||||
if let entities = entities {
|
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 {
|
} else if !rawText.isEmpty {
|
||||||
attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor)
|
attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor)
|
||||||
} else {
|
} else {
|
||||||
@ -563,6 +563,10 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
} else {
|
} else {
|
||||||
strongSelf.statusNode.pressed = nil
|
strongSelf.statusNode.pressed = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let subject = item.associatedData.subject, case let .messageOptions(_, _, info, _) = subject, case .reply = info.kind {
|
||||||
|
strongSelf.updateIsExtractedToContextPreview(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -369,7 +369,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
let chatController = strongSelf.context.sharedContext.makeChatController(
|
let chatController = strongSelf.context.sharedContext.makeChatController(
|
||||||
context: strongSelf.context,
|
context: strongSelf.context,
|
||||||
chatLocation: .peer(id: strongSelf.context.account.peerId),
|
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,
|
botStart: nil,
|
||||||
mode: .standard(previewing: true)
|
mode: .standard(previewing: true)
|
||||||
)
|
)
|
||||||
@ -543,6 +543,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
contextController.immediateItemsTransitionAnimation = true
|
contextController.immediateItemsTransitionAnimation = true
|
||||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||||
|
}, presentReplyOptions: { _ in
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { [weak self] f in
|
}, updateTextInputStateAndMode: { [weak self] f in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
|||||||
@ -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
@ -30,6 +30,7 @@ import ForwardAccessoryPanelNode
|
|||||||
import ChatOverscrollControl
|
import ChatOverscrollControl
|
||||||
import ChatInputPanelNode
|
import ChatInputPanelNode
|
||||||
import ChatInputContextPanelNode
|
import ChatInputContextPanelNode
|
||||||
|
import TextSelectionNode
|
||||||
|
|
||||||
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
|
||||||
let itemNode: OverlayMediaItemNode
|
let itemNode: OverlayMediaItemNode
|
||||||
@ -392,7 +393,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer()
|
||||||
|
|
||||||
var source: ChatHistoryListSource
|
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)
|
let messages = combineLatest(context.account.postbox.messagesAtIds(messageIds), context.account.postbox.loadedPeerWithId(context.account.peerId), options)
|
||||||
|> map { messages, accountPeer, options -> ([Message], Int32, Bool) in
|
|> map { messages, accountPeer, options -> ([Message], Int32, Bool) in
|
||||||
var messages = messages
|
var messages = messages
|
||||||
@ -412,28 +413,30 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
var attributes = message.attributes
|
var attributes = message.attributes
|
||||||
attributes = attributes.filter({ attribute in
|
attributes = attributes.filter({ attribute in
|
||||||
if attribute is EditedMessageAttribute {
|
if case .forward = info.kind {
|
||||||
return false
|
if attribute is EditedMessageAttribute {
|
||||||
}
|
return false
|
||||||
if let attribute = attribute as? ReplyMessageAttribute {
|
}
|
||||||
if !forwardedMessageIds.contains(attribute.messageId) || hideNames {
|
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
|
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
|
return true
|
||||||
})
|
})
|
||||||
@ -2965,6 +2968,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
switch self.chatPresentationInterfaceState.mode {
|
switch self.chatPresentationInterfaceState.mode {
|
||||||
case .standard(previewing: true):
|
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 {
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,10 +17,10 @@ func accessoryPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceS
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch chatPresentationInterfaceState.subject {
|
switch chatPresentationInterfaceState.subject {
|
||||||
case .pinnedMessages, .forwardedMessages:
|
case .pinnedMessages, .messageOptions:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if let editMessage = chatPresentationInterfaceState.interfaceState.editMessage {
|
if let editMessage = chatPresentationInterfaceState.interfaceState.editMessage {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
|
|||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .forwardedMessages = chatPresentationInterfaceState.subject {
|
if case .messageOptions = chatPresentationInterfaceState.subject {
|
||||||
return (nil, nil)
|
return (nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ struct ChatNavigationButton: Equatable {
|
|||||||
|
|
||||||
func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, subject: ChatControllerSubject?, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?) -> ChatNavigationButton? {
|
func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, subject: ChatControllerSubject?, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?) -> ChatNavigationButton? {
|
||||||
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
||||||
if case .forwardedMessages = presentationInterfaceState.subject {
|
if case .messageOptions = presentationInterfaceState.subject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let _ = presentationInterfaceState.reportReason {
|
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? {
|
func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?, moreInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
|
||||||
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
||||||
if case .forwardedMessages = presentationInterfaceState.subject {
|
if case .messageOptions = presentationInterfaceState.subject {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if let currentButton = currentButton, currentButton.action == .cancelMessageSelection {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
|
|||||||
|
|
||||||
var inhibitTitlePanelDisplay = false
|
var inhibitTitlePanelDisplay = false
|
||||||
switch chatPresentationInterfaceState.subject {
|
switch chatPresentationInterfaceState.subject {
|
||||||
case .forwardedMessages:
|
case .messageOptions:
|
||||||
return nil
|
return nil
|
||||||
case .scheduledMessages, .pinnedMessages:
|
case .scheduledMessages, .pinnedMessages:
|
||||||
inhibitTitlePanelDisplay = true
|
inhibitTitlePanelDisplay = true
|
||||||
|
|||||||
@ -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
|
needsShareButton = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1438,7 +1438,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
var transition: ContainedViewLayoutTransition = .immediate
|
var transition: ContainedViewLayoutTransition = .immediate
|
||||||
if case let .System(duration, _) = animation {
|
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)
|
transition = .animated(duration: duration, curve: .linear)
|
||||||
} else {
|
} else {
|
||||||
transition = .animated(duration: duration, curve: .spring)
|
transition = .animated(duration: duration, curve: .spring)
|
||||||
|
|||||||
@ -378,7 +378,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
let textBlockQuoteFont = Font.regular(fontSize)
|
let textBlockQuoteFont = Font.regular(fontSize)
|
||||||
|
|
||||||
var incoming = message.effectivelyIncoming(context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1122,6 +1122,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
}
|
}
|
||||||
self.replyRecognizer = replyRecognizer
|
self.replyRecognizer = replyRecognizer
|
||||||
self.view.addGestureRecognizer(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) {
|
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 {
|
do {
|
||||||
let peerId = chatLocationPeerId
|
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
|
displayAuthorInfo = false
|
||||||
} else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
} else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
||||||
if let forwardInfo = item.content.firstMessage.forwardInfo {
|
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
|
needsShareButton = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1904,7 +1909,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dateFormat: MessageTimestampStatusFormat
|
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
|
dateFormat = .minimal
|
||||||
} else {
|
} else {
|
||||||
dateFormat = .regular
|
dateFormat = .regular
|
||||||
@ -2697,7 +2702,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
if case let .System(duration, _) = animation {
|
if case let .System(duration, _) = animation {
|
||||||
legacyTransition = .animated(duration: duration, curve: .spring)
|
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
|
useDisplayLinkAnimations = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3525,6 +3530,15 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
strongSelf.mainContextSourceNode.layoutUpdated?(strongSelf.mainContextSourceNode.bounds.size, animation)
|
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()
|
strongSelf.updateSearchTextHighlightState()
|
||||||
|
|
||||||
if let (_, f) = strongSelf.awaitingAppliedReaction {
|
if let (_, f) = strongSelf.awaitingAppliedReaction {
|
||||||
@ -3532,7 +3546,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||||||
|
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
|
override func updateAccessibilityData(_ accessibilityData: ChatMessageAccessibilityData) {
|
||||||
|
|||||||
@ -96,7 +96,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -106,7 +106,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
let statusType: ChatMessageDateAndStatusType?
|
let statusType: ChatMessageDateAndStatusType?
|
||||||
|
|||||||
@ -185,7 +185,7 @@ class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -176,7 +176,7 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
needsShareButton = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -235,7 +235,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
var updatedMuteIconImage: UIImage?
|
var updatedMuteIconImage: UIImage?
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ public enum ChatMessageItemContent: Sequence {
|
|||||||
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)])
|
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)])
|
||||||
|
|
||||||
func effectivelyIncoming(_ accountPeerId: PeerId, associatedData: ChatMessageItemAssociatedData? = nil) -> Bool {
|
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
|
return false
|
||||||
}
|
}
|
||||||
switch self {
|
switch self {
|
||||||
@ -420,7 +420,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
self.avatarHeader = avatarHeader
|
self.avatarHeader = avatarHeader
|
||||||
|
|
||||||
var headers: [ListViewItemHeader] = [self.dateHeader]
|
var headers: [ListViewItemHeader] = [self.dateHeader]
|
||||||
if case .forwardedMessages = associatedData.subject {
|
if case .messageOptions = associatedData.subject {
|
||||||
headers = []
|
headers = []
|
||||||
}
|
}
|
||||||
if let avatarHeader = self.avatarHeader {
|
if let avatarHeader = self.avatarHeader {
|
||||||
|
|||||||
@ -92,7 +92,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
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
|
incoming = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
needsShareButton = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,7 @@ final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, forwardMessages: { _ in
|
}, forwardMessages: { _ in
|
||||||
}, updateForwardOptionsState: { _ in
|
}, updateForwardOptionsState: { _ in
|
||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
|
}, presentReplyOptions: { _ in
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
}, updateTextInputStateAndMode: { _ in
|
}, updateTextInputStateAndMode: { _ in
|
||||||
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in
|
}, updateInputModeAndDismissedButtonKeyboardMessageId: { _ in
|
||||||
|
|||||||
@ -310,6 +310,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, forwardMessages: { _ in
|
}, forwardMessages: { _ in
|
||||||
}, updateForwardOptionsState: { _ in
|
}, updateForwardOptionsState: { _ in
|
||||||
}, presentForwardOptions: { _ in
|
}, presentForwardOptions: { _ in
|
||||||
|
}, presentReplyOptions: { _ in
|
||||||
}, shareSelectedMessages: {
|
}, shareSelectedMessages: {
|
||||||
shareMessages()
|
shareMessages()
|
||||||
}, updateTextInputStateAndMode: { _ in
|
}, updateTextInputStateAndMode: { _ in
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import TextNodeWithEntities
|
|||||||
import AnimationCache
|
import AnimationCache
|
||||||
import MultiAnimationRenderer
|
import MultiAnimationRenderer
|
||||||
import AccessoryPanelNode
|
import AccessoryPanelNode
|
||||||
|
import TelegramNotices
|
||||||
|
|
||||||
final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
||||||
private let messageDisposable = MetaDisposable()
|
private let messageDisposable = MetaDisposable()
|
||||||
@ -286,7 +287,11 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) {
|
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.theme = theme
|
||||||
|
|
||||||
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(theme), for: [])
|
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 {
|
if case .ended = recognizer.state {
|
||||||
self.interfaceInteraction?.navigateToMessage(self.messageId, false, true, .generic)
|
self.interfaceInteraction?.navigateToMessage(self.messageId, false, true, .generic)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user