From 8691bfd95e563f88fed5aef2ee249eda38163c7b Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 3 Sep 2019 16:01:24 +0400 Subject: [PATCH 1/2] Fix context menu on sticker items --- .../TelegramUI/ChatController.swift | 7 +- .../ChatMessageAnimatedStickerItemNode.swift | 249 ++++++++++-------- .../ChatMessageInteractiveMediaNode.swift | 2 +- 3 files changed, 137 insertions(+), 121 deletions(-) diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 3106dd9b58..44a393b825 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -526,6 +526,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) { (strongSelf.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures() + strongSelf.chatDisplayNode.cancelInteractiveKeyboardGestures() var updatedMessages = messages for i in 0 ..< updatedMessages.count { if updatedMessages[i].id == message.id { @@ -562,7 +563,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if Namespaces.Message.allScheduled.contains(message.id.namespace) { reactionItems = [] } - let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextControllerContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: reactionItems, recognizer: recognizer) + let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: reactionItems, recognizer: recognizer) strongSelf.currentContextController = controller controller.reactionSelected = { [weak controller] value in guard let strongSelf = self, let message = updatedMessages.first else { @@ -1391,7 +1392,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }))) - let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextControllerContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: [], recognizer: nil) + let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: [], recognizer: nil) strongSelf.currentContextController = controller strongSelf.window?.presentInGlobalOverlay(controller) }) @@ -1431,7 +1432,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G f(.dismissWithoutContent) }))) - let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextControllerContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: [], recognizer: nil) + let controller = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: ChatMessageContextExtractedContentSource(chatNode: strongSelf.chatDisplayNode, message: message), items: actions, reactionItems: [], recognizer: nil) strongSelf.currentContextController = controller strongSelf.window?.presentInGlobalOverlay(controller) }) diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift index ff94def414..5ad94121a6 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageAnimatedStickerItemNode.swift @@ -190,6 +190,15 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } return .waitForSingleTap } + recognizer.longTap = { [weak self] point, recognizer in + guard let strongSelf = self else { + return + } + //strongSelf.reactionRecognizer?.cancel() + if strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) { + recognizer.cancel() + } + } self.view.addGestureRecognizer(recognizer) let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:))) @@ -736,129 +745,135 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { switch recognizer.state { case .ended: if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - switch gesture { - case .tap: - if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) { - if let item = self.item, let author = item.content.firstMessage.author { - var openPeerId = item.effectiveAuthorId ?? author.id - var navigate: ChatControllerInteractionNavigateToPeer - - if item.content.firstMessage.id.peerId == item.context.account.peerId { - navigate = .chat(textInputState: nil, subject: nil) - } else { - navigate = .info - } - - for attribute in item.content.firstMessage.attributes { - if let attribute = attribute as? SourceReferenceMessageAttribute { - openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) - } - } - - if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty { - item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame) - } else { - if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil { - if case .member = channel.participationStatus { - } else { - item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame) - return - } - } - item.controllerInteraction.openPeer(openPeerId, navigate, item.message) - } - } - return - } - - if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) { - if let item = self.item { - for attribute in item.message.attributes { - if let attribute = attribute as? InlineBotMessageAttribute { - var botAddressName: String? - if let peerId = attribute.peerId, let botPeer = item.message.peers[peerId], let addressName = botPeer.addressName { - botAddressName = addressName - } else { - botAddressName = attribute.title - } - - if let botAddressName = botAddressName { - item.controllerInteraction.updateInputState { textInputState in - return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " ")) - } - item.controllerInteraction.updateInputMode { _ in - return .text - } - } - return - } - } - } - } - - if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) { - if let item = self.item { - for attribute in item.message.attributes { - if let attribute = attribute as? ReplyMessageAttribute { - item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId) - return - } - } - } - } - - if let item = self.item, self.imageNode.frame.contains(location) { - if self.telegramFile != nil { - let _ = item.controllerInteraction.openMessage(item.message, .default) - } else if let _ = self.emojiFile { - var startTime: Signal - if self.animationNode.playIfNeeded() { - startTime = .single(0.0) - } else { - startTime = self.animationNode.status - |> map { $0.timestamp } - |> take(1) - |> deliverOnMainQueue - } - - if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { - let _ = startTime.start(next: { [weak self] time in - guard let strongSelf = self else { - return - } - - let heartbeatHaptic: ChatMessageHeartbeatHaptic - if let current = strongSelf.heartbeatHaptic { - heartbeatHaptic = current - } else { - heartbeatHaptic = ChatMessageHeartbeatHaptic() - heartbeatHaptic.enabled = true - strongSelf.heartbeatHaptic = heartbeatHaptic - } - if !heartbeatHaptic.active { - heartbeatHaptic.start(time: time) - } - }) - } - } - return - } - - self.item?.controllerInteraction.clickThroughMessage() - case .longTap, .doubleTap: - if let item = self.item, self.imageNode.frame.contains(location) { - item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil) - } - case .hold: - break - } + let _ = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) } default: break } } + private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> Bool { + switch gesture { + case .tap: + if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) { + if let item = self.item, let author = item.content.firstMessage.author { + var openPeerId = item.effectiveAuthorId ?? author.id + var navigate: ChatControllerInteractionNavigateToPeer + + if item.content.firstMessage.id.peerId == item.context.account.peerId { + navigate = .chat(textInputState: nil, subject: nil) + } else { + navigate = .info + } + + for attribute in item.content.firstMessage.attributes { + if let attribute = attribute as? SourceReferenceMessageAttribute { + openPeerId = attribute.messageId.peerId + navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) + } + } + + if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty { + item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame) + } else { + if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil { + if case .member = channel.participationStatus { + } else { + item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame) + return true + } + } + item.controllerInteraction.openPeer(openPeerId, navigate, item.message) + } + } + return true + } + + if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) { + if let item = self.item { + for attribute in item.message.attributes { + if let attribute = attribute as? InlineBotMessageAttribute { + var botAddressName: String? + if let peerId = attribute.peerId, let botPeer = item.message.peers[peerId], let addressName = botPeer.addressName { + botAddressName = addressName + } else { + botAddressName = attribute.title + } + + if let botAddressName = botAddressName { + item.controllerInteraction.updateInputState { textInputState in + return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " ")) + } + item.controllerInteraction.updateInputMode { _ in + return .text + } + } + return true + } + } + } + } + + if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) { + if let item = self.item { + for attribute in item.message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId) + return true + } + } + } + } + + if let item = self.item, self.imageNode.frame.contains(location) { + if self.telegramFile != nil { + let _ = item.controllerInteraction.openMessage(item.message, .default) + } else if let _ = self.emojiFile { + var startTime: Signal + if self.animationNode.playIfNeeded() { + startTime = .single(0.0) + } else { + startTime = self.animationNode.status + |> map { $0.timestamp } + |> take(1) + |> deliverOnMainQueue + } + + if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, firstScalar.value == 0x2764 { + let _ = startTime.start(next: { [weak self] time in + guard let strongSelf = self else { + return + } + + let heartbeatHaptic: ChatMessageHeartbeatHaptic + if let current = strongSelf.heartbeatHaptic { + heartbeatHaptic = current + } else { + heartbeatHaptic = ChatMessageHeartbeatHaptic() + heartbeatHaptic.enabled = true + strongSelf.heartbeatHaptic = heartbeatHaptic + } + if !heartbeatHaptic.active { + heartbeatHaptic.start(time: time) + } + }) + } + } + return true + } + + self.item?.controllerInteraction.clickThroughMessage() + case .longTap, .doubleTap: + if let item = self.item, self.imageNode.frame.contains(location) { + item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil) + return false + } + case .hold: + break + } + return true + } + @objc func shareButtonPressed() { if let item = self.item { if item.content.firstMessage.id.peerId == item.context.account.peerId { diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift index 38167f7ae0..4d23ae3178 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -832,7 +832,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio } strongSelf.fetchDisposable.set(visibilityAwareFetchSignal.start()) } - } else if case .prefetch = automaticDownload, message.id.namespace != Namespaces.Message.SecretIncoming { + } else if case .prefetch = automaticDownload, message.id.namespace != Namespaces.Message.SecretIncoming && message.id.namespace != Namespaces.Message.Local { if let file = media as? TelegramMediaFile { let fetchSignal = preloadVideoResource(postbox: context.account.postbox, resourceReference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource), duration: 4.0) let visibilityAwareFetchSignal = strongSelf.visibilityPromise.get() From 747ccfa12d7648e62cb0a5c9efc7dae9a19bc089 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Tue, 3 Sep 2019 16:01:47 +0400 Subject: [PATCH 2/2] Fix context menu --- .../ChatMessageStickerItemNode.swift | 186 ++++++++++-------- 1 file changed, 101 insertions(+), 85 deletions(-) diff --git a/submodules/TelegramUI/TelegramUI/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/TelegramUI/ChatMessageStickerItemNode.swift index 94f7216bb5..f2ff3a5dcb 100644 --- a/submodules/TelegramUI/TelegramUI/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/TelegramUI/ChatMessageStickerItemNode.swift @@ -80,6 +80,15 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } return .waitForSingleTap } + recognizer.longTap = { [weak self] point, recognizer in + guard let strongSelf = self else { + return + } + //strongSelf.reactionRecognizer?.cancel() + if strongSelf.gestureRecognized(gesture: .longTap, location: point, recognizer: recognizer) { + recognizer.cancel() + } + } self.view.addGestureRecognizer(recognizer) let replyRecognizer = ChatSwipeToReplyRecognizer(target: self, action: #selector(self.swipeToReplyGesture(_:))) @@ -577,97 +586,104 @@ class ChatMessageStickerItemNode: ChatMessageItemView { @objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { switch recognizer.state { - case .ended: - if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { - switch gesture { - case .tap: - if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) { - if let item = self.item, let author = item.content.firstMessage.author { - var openPeerId = item.effectiveAuthorId ?? author.id - var navigate: ChatControllerInteractionNavigateToPeer - - if item.content.firstMessage.id.peerId == item.context.account.peerId { - navigate = .chat(textInputState: nil, subject: nil) - } else { - navigate = .info - } - - for attribute in item.content.firstMessage.attributes { - if let attribute = attribute as? SourceReferenceMessageAttribute { - openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) - } - } - - if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty { - item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame) - } else { - if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil { - if case .member = channel.participationStatus { - } else { - item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame) - return - } - } - item.controllerInteraction.openPeer(openPeerId, navigate, item.message) - } - } - return - } - - if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) { - if let item = self.item { - for attribute in item.message.attributes { - if let attribute = attribute as? InlineBotMessageAttribute { - var botAddressName: String? - if let peerId = attribute.peerId, let botPeer = item.message.peers[peerId], let addressName = botPeer.addressName { - botAddressName = addressName - } else { - botAddressName = attribute.title - } - - if let botAddressName = botAddressName { - item.controllerInteraction.updateInputState { textInputState in - return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " ")) - } - item.controllerInteraction.updateInputMode { _ in - return .text - } - } - return - } - } - } - } - - if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) { - if let item = self.item { - for attribute in item.message.attributes { - if let attribute = attribute as? ReplyMessageAttribute { - item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId) - return - } - } - } - } - - if let item = self.item, self.imageNode.frame.contains(location) { - let _ = item.controllerInteraction.openMessage(item.message, .default) - return - } + case .ended: + if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation { + let _ = self.gestureRecognized(gesture: gesture, location: location, recognizer: nil) + } + default: + break + } + } + + private func gestureRecognized(gesture: TapLongTapOrDoubleTapGesture, location: CGPoint, recognizer: TapLongTapOrDoubleTapGestureRecognizer?) -> Bool { + switch gesture { + case .tap: + if let avatarNode = self.accessoryItemNode as? ChatMessageAvatarAccessoryItemNode, avatarNode.frame.contains(location) { + if let item = self.item, let author = item.content.firstMessage.author { + var openPeerId = item.effectiveAuthorId ?? author.id + var navigate: ChatControllerInteractionNavigateToPeer - self.item?.controllerInteraction.clickThroughMessage() - case .longTap, .doubleTap: - if let item = self.item, self.imageNode.frame.contains(location) { - item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, nil) + if item.content.firstMessage.id.peerId == item.context.account.peerId { + navigate = .chat(textInputState: nil, subject: nil) + } else { + navigate = .info + } + + for attribute in item.content.firstMessage.attributes { + if let attribute = attribute as? SourceReferenceMessageAttribute { + openPeerId = attribute.messageId.peerId + navigate = .chat(textInputState: nil, subject: .message(attribute.messageId)) } - case .hold: - break + } + + if item.effectiveAuthorId?.namespace == Namespaces.Peer.Empty { + item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, item.presentationData.strings.Conversation_ForwardAuthorHiddenTooltip, self, avatarNode.frame) + } else { + if let channel = item.content.firstMessage.forwardInfo?.author as? TelegramChannel, channel.username == nil { + if case .member = channel.participationStatus { + } else { + item.controllerInteraction.displayMessageTooltip(item.message.id, item.presentationData.strings.Conversation_PrivateChannelTooltip, self, avatarNode.frame) + return true + } + } + item.controllerInteraction.openPeer(openPeerId, navigate, item.message) + } + } + return true + } + + if let viaBotNode = self.viaBotNode, viaBotNode.frame.contains(location) { + if let item = self.item { + for attribute in item.message.attributes { + if let attribute = attribute as? InlineBotMessageAttribute { + var botAddressName: String? + if let peerId = attribute.peerId, let botPeer = item.message.peers[peerId], let addressName = botPeer.addressName { + botAddressName = addressName + } else { + botAddressName = attribute.title + } + + if let botAddressName = botAddressName { + item.controllerInteraction.updateInputState { textInputState in + return ChatTextInputState(inputText: NSAttributedString(string: "@" + botAddressName + " ")) + } + item.controllerInteraction.updateInputMode { _ in + return .text + } + } + return true + } + } } } - default: + + if let replyInfoNode = self.replyInfoNode, replyInfoNode.frame.contains(location) { + if let item = self.item { + for attribute in item.message.attributes { + if let attribute = attribute as? ReplyMessageAttribute { + item.controllerInteraction.navigateToMessage(item.message.id, attribute.messageId) + return true + } + } + } + } + + if let item = self.item, self.imageNode.frame.contains(location) { + let _ = item.controllerInteraction.openMessage(item.message, .default) + return true + } + + self.item?.controllerInteraction.clickThroughMessage() + case .longTap, .doubleTap: + if let item = self.item, self.imageNode.frame.contains(location) { + item.controllerInteraction.openMessageContextMenu(item.message, false, self, self.imageNode.frame, recognizer) + return false + } + case .hold: break } + + return true } @objc func shareButtonPressed() {