diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 866de607c7..c41a797aa7 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -3237,10 +3237,17 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController override public func toolbarActionSelected(action: ToolbarActionOption) { let peerIds = self.chatListDisplayNode.containerNode.currentItemNode.currentState.selectedPeerIds + let threadIds = self.chatListDisplayNode.containerNode.currentItemNode.currentState.selectedThreadIds if case .left = action { let signal: Signal var completion: (() -> Void)? - if !peerIds.isEmpty { + if !threadIds.isEmpty, case let .forum(peerId) = self.location { + self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingItemId(ChatListNodeState.ItemId(peerId: peerId, threadId: threadIds.first!)) + completion = { [weak self] in + self?.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingItemId(nil) + } + signal = self.context.engine.messages.markForumThreadsAsRead(peerId: peerId, threadIds: Array(threadIds)) + } else if !peerIds.isEmpty { self.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingItemId(ChatListNodeState.ItemId(peerId: peerIds.first!, threadId: nil)) completion = { [weak self] in self?.chatListDisplayNode.containerNode.currentItemNode.setCurrentRemovingItemId(nil) diff --git a/submodules/ChatListUI/Sources/ChatListSelection.swift b/submodules/ChatListUI/Sources/ChatListSelection.swift index 55ca691c4c..36adf5dfae 100644 --- a/submodules/ChatListUI/Sources/ChatListSelection.swift +++ b/submodules/ChatListUI/Sources/ChatListSelection.swift @@ -59,17 +59,31 @@ func chatListSelectionOptions(context: AccountContext, peerIds: Set, fil func forumSelectionOptions(context: AccountContext, peerId: PeerId, threadIds: Set, canDelete: Bool) -> Signal { - if threadIds.isEmpty { - return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.PeerReadCounters(id: peerId)) - |> map { counters -> ChatListSelectionOptions in + let threadIdsArray = Array(threadIds) + + var threadSignals: [Signal] = [] + for threadId in threadIdsArray { + threadSignals.append( + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThreadData(id: peerId, threadId: threadId)) + ) + } + + return combineLatest(threadSignals) + |> map { threadDatas -> ChatListSelectionOptions in + if threadIds.isEmpty { + return ChatListSelectionOptions(read: .selective(enabled: false), delete: false) + } else { var hasUnread = false - if counters.isUnread { - hasUnread = true + for thread in threadDatas { + guard let thread = thread else { + continue + } + if thread.incomingUnreadCount > 0 { + hasUnread = true + break + } } - return ChatListSelectionOptions(read: .all(enabled: hasUnread), delete: false) + return ChatListSelectionOptions(read: .selective(enabled: hasUnread), delete: canDelete) } - |> distinctUntilChanged - } else { - return .single(ChatListSelectionOptions(read: .selective(enabled: false), delete: canDelete)) } } diff --git a/submodules/Display/Source/TapLongTapOrDoubleTapGestureRecognizer.swift b/submodules/Display/Source/TapLongTapOrDoubleTapGestureRecognizer.swift index d5993751d1..a6e37daf86 100644 --- a/submodules/Display/Source/TapLongTapOrDoubleTapGestureRecognizer.swift +++ b/submodules/Display/Source/TapLongTapOrDoubleTapGestureRecognizer.swift @@ -196,18 +196,9 @@ public final class TapLongTapOrDoubleTapGestureRecognizer: UIGestureRecognizer, self.highlight?(touchLocation) } - if let hitResult = self.view?.hitTest(touch.location(in: self.view), with: event) { - var fail = false - if let _ = hitResult as? UIButton { - fail = true - } else if let node = hitResult.asyncdisplaykit_node, node is ASControlNode { - fail = true - } - - if fail { - self.state = .failed - return - } + if let hitResult = self.view?.hitTest(touch.location(in: self.view), with: event), let _ = hitResult as? UIButton { + self.state = .failed + return } self.tapCount += 1 diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index ee8beb0a8e..542773a5d3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -472,6 +472,15 @@ public extension TelegramEngine { |> ignoreValues } + public func markForumThreadsAsRead(peerId: EnginePeer.Id, threadIds: [Int64]) -> Signal { + return self.account.postbox.transaction { transaction -> Void in + for threadId in threadIds { + _internal_markForumThreadAsReadInteractively(transaction: transaction, network: self.account.network, viewTracker: self.account.viewTracker, peerId: peerId, threadId: threadId) + } + } + |> ignoreValues + } + public func debugAddHoles() -> Signal { return self.account.postbox.transaction { transaction -> Void in transaction.addHolesEverywhere(peerNamespaces: [Namespaces.Peer.CloudUser, Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel], holeNamespace: Namespaces.Message.Cloud) diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 9b00eecb88..d35aca0391 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -392,6 +392,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) { return .fail } + if let threadInfoNode = strongSelf.threadInfoNode, threadInfoNode.frame.contains(point) { + if let _ = threadInfoNode.hitTest(strongSelf.view.convert(point, to: threadInfoNode.view), with: nil) { + return .fail + } + } if let reactionButtonsNode = strongSelf.reactionButtonsNode { if let _ = reactionButtonsNode.hitTest(strongSelf.view.convert(point, to: reactionButtonsNode.view), with: nil) { return .fail @@ -2492,13 +2497,14 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let shareButtonNode = self.shareButtonNode, shareButtonNode.frame.contains(point) { return shareButtonNode.view } - + if let threadInfoNode = self.threadInfoNode, let result = threadInfoNode.hitTest(self.view.convert(point, to: threadInfoNode.view), with: event) { + return result + } if let reactionButtonsNode = self.reactionButtonsNode { if let result = reactionButtonsNode.hitTest(self.view.convert(point, to: reactionButtonsNode.view), with: event) { return result } } - return super.hitTest(point, with: event) } diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index be0ba68e67..82e1245dcd 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1968,28 +1968,30 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode hasReply = false } - if headerSize.height.isZero { - headerSize.height += 14.0 - } else { - headerSize.height += 5.0 + if !mergedTop.merged { + if headerSize.height.isZero { + headerSize.height += 14.0 + } else { + headerSize.height += 5.0 + } + let sizeAndApply = threadInfoLayout(ChatMessageThreadInfoNode.Arguments( + presentationData: item.presentationData, + strings: item.presentationData.strings, + context: item.context, + controllerInteraction: item.controllerInteraction, + type: .bubble(incoming: incoming), + message: replyMessage, + parentMessage: item.message, + constrainedSize: CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude), + animationCache: item.controllerInteraction.presentationContext.animationCache, + animationRenderer: item.controllerInteraction.presentationContext.animationRenderer + )) + threadInfoSizeApply = (sizeAndApply.0, { synchronousLoads in sizeAndApply.1(synchronousLoads) }) + + threadInfoOriginY = headerSize.height + headerSize.width = max(headerSize.width, threadInfoSizeApply.0.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right) + headerSize.height += threadInfoSizeApply.0.height + 5.0 } - let sizeAndApply = threadInfoLayout(ChatMessageThreadInfoNode.Arguments( - presentationData: item.presentationData, - strings: item.presentationData.strings, - context: item.context, - controllerInteraction: item.controllerInteraction, - type: .bubble(incoming: incoming), - message: replyMessage, - parentMessage: item.message, - constrainedSize: CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude), - animationCache: item.controllerInteraction.presentationContext.animationCache, - animationRenderer: item.controllerInteraction.presentationContext.animationRenderer - )) - threadInfoSizeApply = (sizeAndApply.0, { synchronousLoads in sizeAndApply.1(synchronousLoads) }) - - threadInfoOriginY = headerSize.height - headerSize.width = max(headerSize.width, threadInfoSizeApply.0.width + layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right) - headerSize.height += threadInfoSizeApply.0.height + 5.0 } if !isInstantVideo, let replyMessage = replyMessage, hasReply { diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 588d539e08..b64875f020 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -121,6 +121,11 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs } } + var sameThread = true + if lhs.threadId != rhs.threadId { + sameThread = false + } + var sameAuthor = false if lhsEffectiveAuthor?.id == rhsEffectiveAuthor?.id && lhs.effectivelyIncoming(accountPeerId) == rhs.effectivelyIncoming(accountPeerId) { sameAuthor = true @@ -155,7 +160,7 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs } } - if abs(lhsEffectiveTimestamp - rhsEffectiveTimestamp) < Int32(10 * 60) && sameAuthor { + if abs(lhsEffectiveTimestamp - rhsEffectiveTimestamp) < Int32(10 * 60) && sameAuthor && sameThread { if let channel = lhs.peers[lhs.id.peerId] as? TelegramChannel, case .group = channel.info, lhsEffectiveAuthor?.id == channel.id, !lhs.effectivelyIncoming(accountPeerId) { return .none } diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index a3a2ea0afd..104d177ce0 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -192,7 +192,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let shareButtonNode = strongSelf.shareButtonNode, shareButtonNode.frame.contains(point) { return .fail } - + if let threadInfoNode = strongSelf.threadInfoNode, threadInfoNode.frame.contains(point) { + if let _ = threadInfoNode.hitTest(strongSelf.view.convert(point, to: threadInfoNode.view), with: nil) { + return .fail + } + } if let reactionButtonsNode = strongSelf.reactionButtonsNode { if let _ = reactionButtonsNode.hitTest(strongSelf.view.convert(point, to: reactionButtonsNode.view), with: nil) { return .fail @@ -1444,13 +1448,14 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let shareButtonNode = self.shareButtonNode, shareButtonNode.frame.contains(point) { return shareButtonNode.view } - + if let threadInfoNode = self.threadInfoNode, let result = threadInfoNode.hitTest(self.view.convert(point, to: threadInfoNode.view), with: event) { + return result + } if let reactionButtonsNode = self.reactionButtonsNode { if let result = reactionButtonsNode.hitTest(self.view.convert(point, to: reactionButtonsNode.view), with: event) { return result } } - return super.hitTest(point, with: event) } diff --git a/submodules/TelegramUI/Sources/ChatMessageThreadInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageThreadInfoNode.swift index fb2e900cd7..01c4c66663 100644 --- a/submodules/TelegramUI/Sources/ChatMessageThreadInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageThreadInfoNode.swift @@ -334,7 +334,7 @@ class ChatMessageThreadInfoNode: ASDisplayNode { let colors = topicIconColors(for: topicIconColor) backgroundColor = UIColor(rgb: colors.0.last ?? 0x000000) textColor = UIColor(rgb: colors.1.first ?? 0x000000) - arrowIcon = PresentationResourcesChat.chatBubbleArrowImage(color: textColor) + arrowIcon = PresentationResourcesChat.chatBubbleArrowImage(color: textColor.withAlphaComponent(0.3)) } else { backgroundColor = (incoming ? arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor : arguments.presentationData.theme.theme.chat.message.outgoing.accentTextColor) textColor = incoming ? arguments.presentationData.theme.theme.chat.message.incoming.accentTextColor : arguments.presentationData.theme.theme.chat.message.outgoing.accentTextColor