diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 191118b6e6..f5b8f850df 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -142,7 +142,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable { let primaryPeer: EnginePeer var chatPeer: EnginePeer? let maybeChatPeer = EnginePeer(peer.peer.peers[peer.peer.peerId]!) - if let associatedPeerId = maybeChatPeer._asPeer().associatedPeerId, let associatedPeer = peer.peer.peers[associatedPeerId] { + if case .secretChat = maybeChatPeer, let associatedPeerId = maybeChatPeer._asPeer().associatedPeerId, let associatedPeer = peer.peer.peers[associatedPeerId] { primaryPeer = EnginePeer(associatedPeer) chatPeer = maybeChatPeer } else { @@ -1154,7 +1154,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable { if message.id.peerId == peerId { if let threadId = message.threadId, let threadInfo = threadInfo { - chatThreadInfo = ChatListItemContent.ThreadInfo(id: threadId, info: threadInfo, isOwnedByMe: false, isClosed: false, isHidden: false) + chatThreadInfo = ChatListItemContent.ThreadInfo(id: threadId, info: threadInfo, isOwnedByMe: false, isClosed: false, isHidden: false, threadPeer: nil) index = .forum(pinnedIndex: .none, timestamp: message.index.timestamp, threadId: threadId, namespace: message.index.id.namespace, id: message.index.id.id) } else { index = .chatList(EngineChatList.Item.Index.ChatList(pinningIndex: nil, messageIndex: message.index)) @@ -2748,7 +2748,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { for thread in allAndFoundThreads { if let peer = thread.renderedPeer.peer, let threadData = thread.threadData, case let .forum(_, _, id, _, _) = thread.index { - entries.append(.topic(peer, ChatListItemContent.ThreadInfo(id: id, info: threadData.info, isOwnedByMe: threadData.isOwnedByMe, isClosed: threadData.isClosed, isHidden: threadData.isHidden), index, presentationData.theme, presentationData.strings, .none)) + entries.append(.topic(peer, ChatListItemContent.ThreadInfo(id: id, info: threadData.info, isOwnedByMe: threadData.isOwnedByMe, isClosed: threadData.isClosed, isHidden: threadData.isHidden, threadPeer: nil), index, presentationData.theme, presentationData.strings, .none)) index += 1 } } diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index c44247d813..8f806db72d 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -32,19 +32,43 @@ import MultilineTextWithEntitiesComponent import ShimmerEffect public enum ChatListItemContent { - public struct ThreadInfo: Equatable { - public var id: Int64 - public var info: EngineMessageHistoryThread.Info - public var isOwnedByMe: Bool - public var isClosed: Bool - public var isHidden: Bool + public final class ThreadInfo: Equatable { + public let id: Int64 + public let info: EngineMessageHistoryThread.Info + public let isOwnedByMe: Bool + public let isClosed: Bool + public let isHidden: Bool + public let threadPeer: EnginePeer? - public init(id: Int64, info: EngineMessageHistoryThread.Info, isOwnedByMe: Bool, isClosed: Bool, isHidden: Bool) { + public init(id: Int64, info: EngineMessageHistoryThread.Info, isOwnedByMe: Bool, isClosed: Bool, isHidden: Bool, threadPeer: EnginePeer?) { self.id = id self.info = info self.isOwnedByMe = isOwnedByMe self.isClosed = isClosed self.isHidden = isHidden + self.threadPeer = threadPeer + } + + public static func ==(lhs: ThreadInfo, rhs: ThreadInfo) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.info != rhs.info { + return false + } + if lhs.isOwnedByMe != rhs.isOwnedByMe { + return false + } + if lhs.isClosed != rhs.isClosed { + return false + } + if lhs.isHidden != rhs.isHidden { + return false + } + if lhs.threadPeer != rhs.threadPeer { + return false + } + return true } } @@ -953,23 +977,25 @@ private let loginCodeRegex = try? NSRegularExpression(pattern: "\\b\\d{5,8}\\b", public class ChatListItemNode: ItemListRevealOptionsItemNode { final class TopicItemNode: ASDisplayNode { let topicTitleNode: TextNode - let titleTopicIconView: ComponentHostView - var titleTopicIconComponent: EmojiStatusComponent + let titleTopicIconView: ComponentHostView? + var titleTopicIconComponent: EmojiStatusComponent? var visibilityStatus: Bool = false { didSet { if self.visibilityStatus != oldValue { - let _ = self.titleTopicIconView.update( - transition: .immediate, - component: AnyComponent(self.titleTopicIconComponent.withVisibleForAnimations(self.visibilityStatus)), - environment: {}, - containerSize: self.titleTopicIconView.bounds.size - ) + if let titleTopicIconView = self.titleTopicIconView, let titleTopicIconComponent = self.titleTopicIconComponent { + let _ = titleTopicIconView.update( + transition: .immediate, + component: AnyComponent(titleTopicIconComponent.withVisibleForAnimations(self.visibilityStatus)), + environment: {}, + containerSize: titleTopicIconView.bounds.size + ) + } } } } - private init(topicTitleNode: TextNode, titleTopicIconView: ComponentHostView, titleTopicIconComponent: EmojiStatusComponent) { + private init(topicTitleNode: TextNode, titleTopicIconView: ComponentHostView?, titleTopicIconComponent: EmojiStatusComponent?) { self.topicTitleNode = topicTitleNode self.titleTopicIconView = titleTopicIconView self.titleTopicIconComponent = titleTopicIconComponent @@ -977,60 +1003,72 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { super.init() self.addSubnode(self.topicTitleNode) - self.view.addSubview(self.titleTopicIconView) + if let titleTopicIconView = self.titleTopicIconView { + self.view.addSubview(titleTopicIconView) + } } - static func asyncLayout(_ currentNode: TopicItemNode?) -> (_ constrainedWidth: CGFloat, _ context: AccountContext, _ theme: PresentationTheme, _ threadId: Int64, _ title: NSAttributedString, _ iconId: Int64?, _ iconColor: Int32) -> (CGSize, () -> TopicItemNode) { + static func asyncLayout(_ currentNode: TopicItemNode?) -> (_ constrainedWidth: CGFloat, _ context: AccountContext, _ theme: PresentationTheme, _ threadId: Int64, _ title: NSAttributedString, _ iconId: Int64?, _ iconColor: Int32?) -> (CGSize, () -> TopicItemNode) { let makeTopicTitleLayout = TextNode.asyncLayout(currentNode?.topicTitleNode) return { constrainedWidth, context, theme, threadId, title, iconId, iconColor in - let remainingWidth = max(1.0, constrainedWidth - (18.0 + 2.0)) + let remainingWidth = max(1.0, constrainedWidth - ((iconId == nil ? 1.0 : 18.0) + 2.0)) let topicTitleArguments = TextNodeLayoutArguments(attributedString: title, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: remainingWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 1.0, bottom: 2.0, right: 1.0)) let topicTitleLayout = makeTopicTitleLayout(topicTitleArguments) - return (CGSize(width: 18.0 + 2.0 + topicTitleLayout.0.size.width, height: topicTitleLayout.0.size.height), { + return (CGSize(width: (iconId == nil ? 1.0 : 18.0) + 2.0 + topicTitleLayout.0.size.width, height: topicTitleLayout.0.size.height), { let topicTitleNode = topicTitleLayout.1() - let titleTopicIconView: ComponentHostView - if let current = currentNode?.titleTopicIconView { - titleTopicIconView = current - } else { - titleTopicIconView = ComponentHostView() - } - - let titleTopicIconContent: EmojiStatusComponent.Content + let titleTopicIconContent: EmojiStatusComponent.Content? if threadId == 1 { titleTopicIconContent = .image(image: PresentationResourcesChatList.generalTopicSmallIcon(theme)) } else if let fileId = iconId, fileId != 0 { titleTopicIconContent = .animation(content: .customEmoji(fileId: fileId), size: CGSize(width: 36.0, height: 36.0), placeholderColor: theme.list.mediaPlaceholderColor, themeColor: theme.list.itemAccentColor, loopMode: .count(0)) - } else { + } else if let iconColor { titleTopicIconContent = .topic(title: String(title.string.prefix(1)), color: iconColor, size: CGSize(width: 18.0, height: 18.0)) + } else { + titleTopicIconContent = nil } - let titleTopicIconComponent = EmojiStatusComponent( - context: context, - animationCache: context.animationCache, - animationRenderer: context.animationRenderer, - content: titleTopicIconContent, - isVisibleForAnimations: (currentNode?.visibilityStatus ?? false) && context.sharedContext.energyUsageSettings.loopEmoji, - action: nil - ) + var titleTopicIconComponent: EmojiStatusComponent? + var titleTopicIconView: ComponentHostView? + + if let titleTopicIconContent { + titleTopicIconComponent = EmojiStatusComponent( + context: context, + animationCache: context.animationCache, + animationRenderer: context.animationRenderer, + content: titleTopicIconContent, + isVisibleForAnimations: (currentNode?.visibilityStatus ?? false) && context.sharedContext.energyUsageSettings.loopEmoji, + action: nil + ) + + if let current = currentNode?.titleTopicIconView { + titleTopicIconView = current + } else { + titleTopicIconView = ComponentHostView() + } + } let targetNode = currentNode ?? TopicItemNode(topicTitleNode: topicTitleNode, titleTopicIconView: titleTopicIconView, titleTopicIconComponent: titleTopicIconComponent) targetNode.titleTopicIconComponent = titleTopicIconComponent - let iconSize = titleTopicIconView.update( - transition: .immediate, - component: AnyComponent(titleTopicIconComponent), - environment: {}, - containerSize: CGSize(width: 18.0, height: 18.0) - ) - titleTopicIconView.frame = CGRect(origin: CGPoint(x: 0.0, y: 2.0), size: iconSize) - - topicTitleNode.frame = CGRect(origin: CGPoint(x: 18.0 + 2.0, y: 0.0), size: topicTitleLayout.0.size) + if let titleTopicIconView, let titleTopicIconComponent { + let iconSize = titleTopicIconView.update( + transition: .immediate, + component: AnyComponent(titleTopicIconComponent), + environment: {}, + containerSize: CGSize(width: 18.0, height: 18.0) + ) + titleTopicIconView.frame = CGRect(origin: CGPoint(x: 0.0, y: 2.0), size: iconSize) + + topicTitleNode.frame = CGRect(origin: CGPoint(x: 18.0 + 2.0, y: 0.0), size: topicTitleLayout.0.size) + } else { + topicTitleNode.frame = CGRect(origin: CGPoint(x: 1.0, y: 0.0), size: topicTitleLayout.0.size) + } return targetNode }) @@ -1090,9 +1128,9 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { } } - func asyncLayout() -> (_ context: AccountContext, _ constrainedWidth: CGFloat, _ theme: PresentationTheme, _ authorTitle: NSAttributedString?, _ topics: [(id: Int64, title: NSAttributedString, iconId: Int64?, iconColor: Int32)]) -> (CGSize, () -> CGRect?) { + func asyncLayout() -> (_ context: AccountContext, _ constrainedWidth: CGFloat, _ theme: PresentationTheme, _ authorTitle: NSAttributedString?, _ topics: [(id: Int64, title: NSAttributedString, iconId: Int64?, iconColor: Int32?)]) -> (CGSize, () -> CGRect?) { let makeAuthorLayout = TextNode.asyncLayout(self.authorNode) - var makeExistingTopicLayouts: [Int64: (_ constrainedWidth: CGFloat, _ context: AccountContext, _ theme: PresentationTheme, _ threadId: Int64, _ title: NSAttributedString, _ iconId: Int64?, _ iconColor: Int32) -> (CGSize, () -> TopicItemNode)] = [:] + var makeExistingTopicLayouts: [Int64: (_ constrainedWidth: CGFloat, _ context: AccountContext, _ theme: PresentationTheme, _ threadId: Int64, _ title: NSAttributedString, _ iconId: Int64?, _ iconColor: Int32?) -> (CGSize, () -> TopicItemNode)] = [:] for (topicId, topicNode) in self.topicNodes { makeExistingTopicLayouts[topicId] = TopicItemNode.asyncLayout(topicNode) } @@ -1119,7 +1157,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var topicsSizeAndApply: [(Int64, CGSize, () -> TopicItemNode)] = [] for topic in topics { - if remainingWidth <= 22.0 + 2.0 + 10.0 { + if remainingWidth <= (topic.iconId == nil ? 8.0 : 22.0) + 2.0 + 10.0 { break } @@ -1347,7 +1385,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { } return result case let .peer(peerData): - guard let chatMainPeer = peerData.peer.chatMainPeer else { + guard let chatMainPeer = peerData.peer.chatOrMonoforumMainPeer else { return nil } var result = "" @@ -1394,7 +1432,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var result = "" var isFirst = true for peer in peers { - if let chatMainPeer = peer.peer.chatMainPeer { + if let chatMainPeer = peer.peer.chatOrMonoforumMainPeer { let peerTitle = chatMainPeer.compactDisplayTitle if !peerTitle.isEmpty { if isFirst { @@ -1670,6 +1708,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var peer: EnginePeer? var displayAsMessage = false var enablePreview = true + var peerIsMonoforum = false switch item.content { case .loading: displayAsMessage = true @@ -1679,7 +1718,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { if displayAsMessage, case let .user(author) = peerData.messages.last?.author { peer = .user(author) } else { - peer = peerData.peer.chatMainPeer + peer = peerData.peer.chatOrMonoforumMainPeer + if case let .channel(channel) = peerData.peer.peer, channel.isMonoForum { + peerIsMonoforum = true + } } if peerData.peer.peerId.namespace == Namespaces.Peer.SecretChat { enablePreview = false @@ -1726,6 +1768,9 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { overrideImage = .deletedIcon } var isForumAvatar = false + if peerIsMonoforum { + isForumAvatar = true + } if case let .channel(channel) = peer, channel.isForumOrMonoForum { isForumAvatar = true } @@ -2055,7 +2100,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { topForumTopicItems = topForumTopicItemsValue if item.interaction.searchTextHighightState != nil, threadInfo == nil, topForumTopicItems.isEmpty, let message = messagesValue.first, let threadId = message.threadId, let associatedThreadInfo = message.associatedThreadInfo { - topForumTopicItems = [EngineChatList.ForumTopicData(id: threadId, title: associatedThreadInfo.title, iconFileId: associatedThreadInfo.icon, iconColor: associatedThreadInfo.iconColor, maxOutgoingReadMessageId: message.id, isUnread: false)] + topForumTopicItems = [EngineChatList.ForumTopicData(id: threadId, title: associatedThreadInfo.title, iconFileId: associatedThreadInfo.icon, iconColor: associatedThreadInfo.iconColor, maxOutgoingReadMessageId: message.id, isUnread: false, threadPeer: nil)] } switch peerValue.peer { @@ -2325,7 +2370,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { var contentImageSpecs: [ContentImageSpec] = [] var avatarContentImageSpec: ContentImageSpec? - var forumThread: (id: Int64, title: String, iconId: Int64?, iconColor: Int32, isUnread: Bool)? + var forumThread: (id: Int64, title: String, iconId: Int64?, iconColor: Int32, threadPeer: EnginePeer?, isUnread: Bool)? var displayForwardedIcon = false var displayStoryReplyIcon = false @@ -2393,10 +2438,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { } if let _ = peerText, case let .channel(channel) = itemPeer.chatMainPeer, channel.isForumOrMonoForum, threadInfo == nil { - if let forumTopicData = forumTopicData { - forumThread = (forumTopicData.id, forumTopicData.title, forumTopicData.iconFileId, forumTopicData.iconColor, forumTopicData.isUnread) - } else if let threadInfo = threadInfo { - forumThread = (threadInfo.id, threadInfo.info.title, threadInfo.info.icon, threadInfo.info.iconColor, false) + if let forumTopicData { + forumThread = (forumTopicData.id, forumTopicData.title, forumTopicData.iconFileId, forumTopicData.iconColor, forumTopicData.threadPeer, forumTopicData.isUnread) + } else if let threadInfo { + forumThread = (threadInfo.id, threadInfo.info.title, threadInfo.info.icon, threadInfo.info.iconColor, nil, false) } } @@ -2906,14 +2951,19 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { titleAttributedString = NSAttributedString(string: item.presentationData.strings.DialogList_Replies, font: titleFont, textColor: theme.titleColor) } else if let id = itemPeer.chatMainPeer?.id, id.isAnonymousSavedMessages { titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_AuthorHidden, font: titleFont, textColor: theme.titleColor) - } else if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { + } else if let displayTitle = itemPeer.chatOrMonoforumMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { let textColor: UIColor if case let .chatList(index) = item.index, index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat { textColor = theme.secretTitleColor } else { textColor = theme.titleColor } - titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: textColor) + //TODO:localize + if case let .channel(channel) = itemPeer.peer, channel.flags.contains(.isMonoforum) { + titleAttributedString = NSAttributedString(string: "\(displayTitle) Messages", font: titleFont, textColor: textColor) + } else { + titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: textColor) + } } case .group: titleAttributedString = NSAttributedString(string: item.presentationData.strings.ChatList_ArchivedChatsTitle, font: titleFont, textColor: theme.titleColor) @@ -3271,9 +3321,30 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { let isSearching = item.interaction.searchTextHighightState != nil var isFirstForumThreadSelectable = false - var forumThreads: [(id: Int64, title: NSAttributedString, iconId: Int64?, iconColor: Int32)] = [] + var forumThreads: [(id: Int64, title: NSAttributedString, iconId: Int64?, iconColor: Int32?)] = [] if case .savedMessagesChats = item.chatListLocation { } else if case let .peer(peer) = item.content, case let .channel(channel) = peer.peer.peer, channel.flags.contains(.isMonoforum) { + if forumThread != nil || !topForumTopicItems.isEmpty { + if let forumThread { + isFirstForumThreadSelectable = forumThread.isUnread + forumThreads.append((id: forumThread.id, title: NSAttributedString(string: forumThread.threadPeer?.compactDisplayTitle ?? " ", font: textFont, textColor: forumThread.isUnread || isSearching ? theme.authorNameColor : theme.messageTextColor), iconId: nil, iconColor: nil)) + } + for topicItem in topForumTopicItems { + if forumThread?.id != topicItem.id { + forumThreads.append((id: topicItem.id, title: NSAttributedString(string: topicItem.threadPeer?.compactDisplayTitle ?? " ", font: textFont, textColor: topicItem.isUnread || isSearching ? theme.authorNameColor : theme.messageTextColor), iconId: nil, iconColor: nil)) + } + } + + if let effectiveAuthorTitle, let textAttributedStringValue = textAttributedString { + let mutableTextAttributedString = NSMutableAttributedString() + mutableTextAttributedString.append(NSAttributedString(string: effectiveAuthorTitle.string + ": ", font: textFont, textColor: theme.authorNameColor)) + mutableTextAttributedString.append(textAttributedStringValue) + + textAttributedString = mutableTextAttributedString + } + + effectiveAuthorTitle = nil + } } else if forumThread != nil || !topForumTopicItems.isEmpty { if let forumThread = forumThread { isFirstForumThreadSelectable = forumThread.isUnread diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index 726792f7ab..dfc3361882 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -704,8 +704,8 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState, } var threadInfo: ChatListItemContent.ThreadInfo? - if let threadData = entry.threadData, let threadId = threadId { - threadInfo = ChatListItemContent.ThreadInfo(id: threadId, info: threadData.info, isOwnedByMe: threadData.isOwnedByMe, isClosed: threadData.isClosed, isHidden: threadData.isHidden) + if let threadData = entry.threadData, let threadId { + threadInfo = ChatListItemContent.ThreadInfo(id: threadId, info: threadData.info, isOwnedByMe: threadData.isOwnedByMe, isClosed: threadData.isClosed, isHidden: threadData.isHidden, threadPeer: nil) } let entry: ChatListNodeEntry = .PeerEntry(ChatListNodeEntry.PeerEntryData( @@ -863,7 +863,9 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState, draftState: draftState, mediaDraftContentType: item.item.mediaDraftContentType, peer: item.item.renderedPeer, - threadInfo: item.item.threadData.flatMap { ChatListItemContent.ThreadInfo(id: threadId, info: $0.info, isOwnedByMe: $0.isOwnedByMe, isClosed: $0.isClosed, isHidden: $0.isHidden) }, + threadInfo: item.item.threadData.flatMap { + return ChatListItemContent.ThreadInfo(id: threadId, info: $0.info, isOwnedByMe: $0.isOwnedByMe, isClosed: $0.isClosed, isHidden: $0.isHidden, threadPeer: nil) + }, presence: item.item.presence, hasUnseenMentions: item.item.hasUnseenMentions, hasUnseenReactions: item.item.hasUnseenReactions, diff --git a/submodules/Postbox/Sources/ChatListIndexTable.swift b/submodules/Postbox/Sources/ChatListIndexTable.swift index 510fce50fa..e672c4ced4 100644 --- a/submodules/Postbox/Sources/ChatListIndexTable.swift +++ b/submodules/Postbox/Sources/ChatListIndexTable.swift @@ -198,13 +198,13 @@ final class ChatListIndexTable: Table { } if let previous = previous { - var isThreadBasedUnreadCalculation = postbox.seedConfiguration.peerSummaryIsThreadBased(updated.0) + var isThreadBasedUnreadCalculation = postbox.seedConfiguration.peerSummaryIsThreadBased(updated.0).value if let cachedData = updatedCachedPeerData[updated.0.id]?.1, postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedData) { isThreadBasedUnreadCalculation = false } var wasThreadBasedUnreadCalculation = false - if postbox.seedConfiguration.peerSummaryIsThreadBased(previous.0) { + if postbox.seedConfiguration.peerSummaryIsThreadBased(previous.0).value { if let cachedData = postbox.cachedPeerDataTable.get(previous.0.id), postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedData) { } else { wasThreadBasedUnreadCalculation = true @@ -224,13 +224,13 @@ final class ChatListIndexTable: Table { continue } - var isThreadBasedUnreadCalculation = postbox.seedConfiguration.peerSummaryIsThreadBased(peer) + var isThreadBasedUnreadCalculation = postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value if postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedDataUpdate.1) { isThreadBasedUnreadCalculation = false } var wasThreadBasedUnreadCalculation = false - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { if let previousCachedData = cachedDataUpdate.0, postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(previousCachedData) { } else { wasThreadBasedUnreadCalculation = true @@ -412,7 +412,12 @@ final class ChatListIndexTable: Table { continue } let isContact = postbox.contactsTable.isContact(peerId: peerId) - let notificationPeerId: PeerId = peer.associatedPeerId ?? peerId + let notificationPeerId: PeerId + if let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { + notificationPeerId = associatedPeerId + } else { + notificationPeerId = peerId + } let initialReadState: CombinedPeerReadState? if let updated = updatedIsThreadBasedUnreadCountCalculation[peerId] { @@ -434,7 +439,7 @@ final class ChatListIndexTable: Table { displayAsRegularChat = true } - if let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { + if let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value, !displayAsRegularChat { let previousCount: Int32 if let previousSummary = alteredInitialPeerThreadsSummaries[peerId] { previousCount = previousSummary.effectiveUnreadCount @@ -453,7 +458,7 @@ final class ChatListIndexTable: Table { } let currentReadState: CombinedPeerReadState? - if let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { + if let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value, !displayAsRegularChat { let count = postbox.peerThreadsSummaryTable.get(peerId: peerId)?.effectiveUnreadCount ?? 0 currentReadState = CombinedPeerReadState(states: [(0, .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 1, maxKnownId: 0, count: count, markedUnread: false))]) } else { @@ -686,7 +691,7 @@ final class ChatListIndexTable: Table { } let combinedState: CombinedPeerReadState? - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { let count: Int32 = postbox.peerThreadsSummaryTable.get(peerId: peerId)?.effectiveUnreadCount ?? 0 combinedState = CombinedPeerReadState(states: [(0, .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 1, maxKnownId: 0, count: count, markedUnread: false))]) } else { @@ -698,7 +703,12 @@ final class ChatListIndexTable: Table { } let isContact = postbox.contactsTable.isContact(peerId: peerId) - let notificationPeerId: PeerId = peer.associatedPeerId ?? peerId + let notificationPeerId: PeerId + if let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { + notificationPeerId = associatedPeerId + } else { + notificationPeerId = peerId + } let inclusion = self.get(peerId: peerId) if let (groupId, _) = inclusion.includedIndex(peerId: peerId) { if totalStates[groupId] == nil { @@ -778,7 +788,7 @@ final class ChatListIndexTable: Table { } let combinedState: CombinedPeerReadState? - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { let count: Int32 = postbox.peerThreadsSummaryTable.get(peerId: peerId)?.effectiveUnreadCount ?? 0 combinedState = CombinedPeerReadState(states: [(0, .idBased(maxIncomingReadId: 0, maxOutgoingReadId: 1, maxKnownId: 0, count: count, markedUnread: false))]) } else { diff --git a/submodules/Postbox/Sources/ChatListView.swift b/submodules/Postbox/Sources/ChatListView.swift index fa0fde3d30..c25f25fa95 100644 --- a/submodules/Postbox/Sources/ChatListView.swift +++ b/submodules/Postbox/Sources/ChatListView.swift @@ -100,13 +100,28 @@ public struct ChatListGroupReferenceEntry: Equatable { } } -public struct ChatListForumTopicData: Equatable { - public var id: Int64 - public var info: StoredMessageHistoryThreadInfo +public final class ChatListForumTopicData: Equatable { + public let id: Int64 + public let info: StoredMessageHistoryThreadInfo + public let threadPeer: Peer? - public init(id: Int64, info: StoredMessageHistoryThreadInfo) { + public init(id: Int64, info: StoredMessageHistoryThreadInfo, threadPeer: Peer?) { self.id = id self.info = info + self.threadPeer = threadPeer + } + + public static func ==(lhs: ChatListForumTopicData, rhs: ChatListForumTopicData) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.info != rhs.info { + return false + } + if !arePeersEqual(lhs.threadPeer, rhs.threadPeer) { + return false + } + return true } } @@ -447,7 +462,12 @@ public struct ChatListFilterPredicate { if self.pinnedPeerIds.contains(peer.id) { return false } - let includePeerId = peer.associatedPeerId ?? peer.id + let includePeerId: PeerId + if let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { + includePeerId = associatedPeerId + } else { + includePeerId = peer.id + } if self.excludePeerIds.contains(includePeerId) { return false } @@ -694,7 +714,7 @@ final class MutableChatListView { let renderedPeer = RenderedPeer(peerId: peer.id, peers: peers, associatedMedia: renderAssociatedMediaForPeers(postbox: postbox, peers: peers)) let isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { let hasUnmutedUnread = postbox.peerThreadsSummaryTable.get(peerId: peer.id)?.hasUnmutedUnread ?? false isUnread = hasUnmutedUnread } else { @@ -826,7 +846,7 @@ final class MutableChatListView { displayAsRegularChat = postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedData) } - if let peer = groupEntries[i].renderedPeers[j].peer.peer, postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { + if let peer = groupEntries[i].renderedPeers[j].peer.peer, postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value, !displayAsRegularChat { isUnread = postbox.peerThreadsSummaryTable.get(peerId: peer.id)?.hasUnmutedUnread ?? false } else { isUnread = postbox.readStateTable.getCombinedState(groupEntries[i].renderedPeers[j].peer.peerId)?.isUnread ?? false @@ -904,6 +924,9 @@ final class MutableChatListView { if let associatedPeer = postbox.peerTable.get(associatedPeerId) { peers[associatedPeer.id] = associatedPeer } + } + + if let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { notificationSettings = postbox.peerNotificationSettingsTable.getEffective(associatedPeerId) presence = postbox.peerPresenceTable.get(associatedPeerId) isContact = postbox.contactsTable.isContact(peerId: associatedPeerId) @@ -916,17 +939,25 @@ final class MutableChatListView { let renderedPeer = RenderedPeer(peerId: index.messageIndex.id.peerId, peers: peers, associatedMedia: renderAssociatedMediaForPeers(postbox: postbox, peers: peers)) + var isThreadBased = false + var threadsArePeers = false + if let peer = renderedPeer.peer { + let value = postbox.seedConfiguration.peerSummaryIsThreadBased(peer) + isThreadBased = value.value + threadsArePeers = value.threadsArePeers + } + var forumTopicData: ChatListForumTopicData? if let message = renderedMessages.first, let threadId = message.threadId { if let info = postbox.messageHistoryThreadIndexTable.get(peerId: message.id.peerId, threadId: threadId) { - forumTopicData = ChatListForumTopicData(id: threadId, info: info) + forumTopicData = ChatListForumTopicData(id: threadId, info: info, threadPeer: threadsArePeers ? postbox.peerTable.get(PeerId(threadId)) : nil) } } var topForumTopics: [ChatListForumTopicData] = [] - if let peer = renderedPeer.peer, postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if let peer = renderedPeer.peer, isThreadBased { for item in postbox.messageHistoryThreadIndexTable.fetch(peerId: peer.id, namespace: 0, start: .upperBound, end: .lowerBound, limit: 5) { - topForumTopics.append(ChatListForumTopicData(id: item.threadId, info: item.info)) + topForumTopics.append(ChatListForumTopicData(id: item.threadId, info: item.info, threadPeer: threadsArePeers ? postbox.peerTable.get(PeerId(item.threadId)) : nil)) } } @@ -938,7 +969,7 @@ final class MutableChatListView { displayAsRegularChat = postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedData) } - if let peer = postbox.peerTable.get(index.messageIndex.id.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { + if isThreadBased, !displayAsRegularChat { let summary = postbox.peerThreadsSummaryTable.get(peerId: index.messageIndex.id.peerId) var count: Int32 = 0 var isMuted: Bool = false diff --git a/submodules/Postbox/Sources/ChatListViewState.swift b/submodules/Postbox/Sources/ChatListViewState.swift index ae901e7d20..4743642867 100644 --- a/submodules/Postbox/Sources/ChatListViewState.swift +++ b/submodules/Postbox/Sources/ChatListViewState.swift @@ -65,7 +65,7 @@ private func mappedChatListFilterPredicate(postbox: PostboxImpl, currentTransact if let cachedPeerData = postbox.cachedPeerDataTable.get(peer.id), postbox.seedConfiguration.decodeDisplayPeerAsRegularChat(cachedPeerData) { displayAsRegularChat = true } - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: peer.id)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false @@ -441,7 +441,7 @@ private final class ChatListViewSpaceState { let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, threadId: nil, calculation: filterPredicate.messageTagSummary) var isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(peer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: peer.id)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(index.messageIndex.id.peerId)?.isUnread ?? false @@ -571,7 +571,7 @@ private final class ChatListViewSpaceState { } var isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(entryPeer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(entryPeer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: entryPeer.id)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(entryPeer.id)?.isUnread ?? false @@ -620,7 +620,7 @@ private final class ChatListViewSpaceState { } var isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(mainPeer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(mainPeer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: peerId)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(peerId)?.isUnread ?? false @@ -750,7 +750,7 @@ private final class ChatListViewSpaceState { switch entry { case let .MessageEntry(entryData): var presencePeerId = entryData.renderedPeer.peerId - if let peer = entryData.renderedPeer.peers[entryData.renderedPeer.peerId], let associatedPeerId = peer.associatedPeerId { + if let peer = entryData.renderedPeer.peers[entryData.renderedPeer.peerId], let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { presencePeerId = associatedPeerId } if let presence = transaction.currentUpdatedPeerPresences[presencePeerId] { @@ -802,7 +802,7 @@ private final class ChatListViewSpaceState { } var isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(entryPeer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(entryPeer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: entryPeer.id)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(entryPeer.id)?.isUnread ?? false @@ -860,7 +860,7 @@ private final class ChatListViewSpaceState { } var isUnread: Bool - if postbox.seedConfiguration.peerSummaryIsThreadBased(mainPeer) && !displayAsRegularChat { + if postbox.seedConfiguration.peerSummaryIsThreadBased(mainPeer).value && !displayAsRegularChat { isUnread = (postbox.peerThreadsSummaryTable.get(peerId: peerId)?.effectiveUnreadCount ?? 0) > 0 } else { isUnread = postbox.readStateTable.getCombinedState(peerId)?.isUnread ?? false @@ -954,7 +954,7 @@ private final class ChatListViewSpaceState { } var updatedReadState = entryData.readState - if let peer = postbox.peerTable.get(entryData.index.messageIndex.id.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { + if let peer = postbox.peerTable.get(entryData.index.messageIndex.id.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value, !displayAsRegularChat { let summary = postbox.peerThreadsSummaryTable.get(peerId: peer.id) var count: Int32 = 0 @@ -1534,7 +1534,11 @@ struct ChatListViewState { if let associatedPeer = postbox.peerTable.get(associatedPeerId) { peers[associatedPeer.id] = associatedPeer } - presence = postbox.peerPresenceTable.get(associatedPeerId) + if peer.associatedPeerOverridesIdentity { + presence = postbox.peerPresenceTable.get(associatedPeerId) + } else { + presence = postbox.peerPresenceTable.get(index.messageIndex.id.peerId) + } } else { presence = postbox.peerPresenceTable.get(index.messageIndex.id.peerId) } @@ -1580,10 +1584,18 @@ struct ChatListViewState { } } + var isThreadBased = false + var threadsArePeers = false + if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) { + let value = postbox.seedConfiguration.peerSummaryIsThreadBased(peer) + isThreadBased = value.value + threadsArePeers = value.threadsArePeers + } + var forumTopicData: ChatListForumTopicData? if let message = renderedMessages.first, let threadId = message.threadId { if let info = postbox.messageHistoryThreadIndexTable.get(peerId: message.id.peerId, threadId: threadId) { - forumTopicData = ChatListForumTopicData(id: threadId, info: info) + forumTopicData = ChatListForumTopicData(id: threadId, info: info, threadPeer: threadsArePeers ? postbox.peerTable.get(PeerId(threadId)) : nil) } } @@ -1597,12 +1609,12 @@ struct ChatListViewState { var topForumTopics: [ChatListForumTopicData] = [] let readState: ChatListViewReadState? - if let peer = postbox.peerTable.get(index.messageIndex.id.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer), !displayAsRegularChat { - for item in postbox.messageHistoryThreadIndexTable.fetch(peerId: peer.id, namespace: 0, start: .upperBound, end: .lowerBound, limit: 5) { - topForumTopics.append(ChatListForumTopicData(id: item.threadId, info: item.info)) + if isThreadBased, !displayAsRegularChat { + for item in postbox.messageHistoryThreadIndexTable.fetch(peerId: index.messageIndex.id.peerId, namespace: 0, start: .upperBound, end: .lowerBound, limit: 5) { + topForumTopics.append(ChatListForumTopicData(id: item.threadId, info: item.info, threadPeer: threadsArePeers ? postbox.peerTable.get(PeerId(item.threadId)) : nil)) } - let summary = postbox.peerThreadsSummaryTable.get(peerId: peer.id) + let summary = postbox.peerThreadsSummaryTable.get(peerId: index.messageIndex.id.peerId) var count: Int32 = 0 var isMuted: Bool = false diff --git a/submodules/Postbox/Sources/FileSize.swift b/submodules/Postbox/Sources/FileSize.swift index ef4fc4863a..ea23c12f0d 100644 --- a/submodules/Postbox/Sources/FileSize.swift +++ b/submodules/Postbox/Sources/FileSize.swift @@ -1,5 +1,9 @@ import Foundation +// Incuding at least one Objective-C class in a swift file ensures that it doesn't get stripped by the linker +private final class LinkHelperClass: NSObject { +} + public func fileSize(_ path: String, useTotalFileAllocatedSize: Bool = false) -> Int64? { /*if useTotalFileAllocatedSize { let url = URL(fileURLWithPath: path) diff --git a/submodules/Postbox/Sources/MessageHistoryView.swift b/submodules/Postbox/Sources/MessageHistoryView.swift index 2bd829b5c0..61d5a7cfd2 100644 --- a/submodules/Postbox/Sources/MessageHistoryView.swift +++ b/submodules/Postbox/Sources/MessageHistoryView.swift @@ -900,7 +900,7 @@ final class MutableMessageHistoryView: MutablePostboxView { case let .peerIsContact(peerId, value): if let replacedPeerIds = transaction.replaceContactPeerIds { let updatedValue: Bool - if let contactPeer = postbox.peerTable.get(peerId), let associatedPeerId = contactPeer.associatedPeerId { + if let contactPeer = postbox.peerTable.get(peerId), let associatedPeerId = contactPeer.associatedPeerId, contactPeer.associatedPeerOverridesIdentity { updatedValue = replacedPeerIds.contains(associatedPeerId) } else { updatedValue = replacedPeerIds.contains(peerId) diff --git a/submodules/Postbox/Sources/Peer.swift b/submodules/Postbox/Sources/Peer.swift index 8f339d2b31..e4aed39cd0 100644 --- a/submodules/Postbox/Sources/Peer.swift +++ b/submodules/Postbox/Sources/Peer.swift @@ -298,6 +298,7 @@ public protocol Peer: AnyObject, PostboxCoding { var id: PeerId { get } var indexName: PeerIndexNameRepresentation { get } var associatedPeerId: PeerId? { get } + var associatedPeerOverridesIdentity: Bool { get } var notificationSettingsPeerId: PeerId? { get } var associatedMediaIds: [MediaId]? { get } var timeoutAttribute: UInt32? { get } @@ -305,6 +306,10 @@ public protocol Peer: AnyObject, PostboxCoding { func isEqual(_ other: Peer) -> Bool } +public extension Peer { + var associatedPeerOverridesIdentity: Bool { return false } +} + public func arePeersEqual(_ lhs: Peer?, _ rhs: Peer?) -> Bool { if let lhs = lhs, let rhs = rhs { return lhs.isEqual(rhs) diff --git a/submodules/Postbox/Sources/PeerNotificationSettingsView.swift b/submodules/Postbox/Sources/PeerNotificationSettingsView.swift index c73b3eb6da..7e601431a8 100644 --- a/submodules/Postbox/Sources/PeerNotificationSettingsView.swift +++ b/submodules/Postbox/Sources/PeerNotificationSettingsView.swift @@ -9,7 +9,7 @@ final class MutablePeerNotificationSettingsView: MutablePostboxView { self.notificationSettings = [:] for peerId in peerIds { var notificationPeerId = peerId - if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId { + if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { notificationPeerId = associatedPeerId } if let settings = postbox.peerNotificationSettingsTable.getEffective(notificationPeerId) { @@ -23,7 +23,7 @@ final class MutablePeerNotificationSettingsView: MutablePostboxView { var updated = false for peerId in self.peerIds { var notificationPeerId = peerId - if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId { + if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { notificationPeerId = associatedPeerId } if let (_, settings) = transaction.currentUpdatedPeerNotificationSettings[notificationPeerId] { @@ -41,7 +41,7 @@ final class MutablePeerNotificationSettingsView: MutablePostboxView { /*var notificationSettings: [PeerId: PeerNotificationSettings] = [:] for peerId in self.peerIds { var notificationPeerId = peerId - if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId { + if let peer = postbox.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { notificationPeerId = associatedPeerId } if let settings = postbox.peerNotificationSettingsTable.getEffective(notificationPeerId) { diff --git a/submodules/Postbox/Sources/PeerView.swift b/submodules/Postbox/Sources/PeerView.swift index ba0b94f90e..a8149a6ad9 100644 --- a/submodules/Postbox/Sources/PeerView.swift +++ b/submodules/Postbox/Sources/PeerView.swift @@ -48,7 +48,7 @@ final class MutablePeerView: MutablePostboxView { var messageIds = Set() peerIds.insert(peerId) - if let peer = getPeer(peerId), let associatedPeerId = peer.associatedPeerId { + if let peer = getPeer(peerId), let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { peerIds.insert(associatedPeerId) self.contactPeerId = associatedPeerId self.peerIsContact = postbox.contactsTable.isContact(peerId: associatedPeerId) @@ -76,7 +76,7 @@ final class MutablePeerView: MutablePostboxView { self.memberStoryStats[id] = value } } - if let peer = self.peers[peerId], let associatedPeerId = peer.associatedPeerId { + if let peer = self.peers[peerId], let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { if let peer = getPeer(associatedPeerId) { self.peers[associatedPeerId] = peer } @@ -236,7 +236,7 @@ final class MutablePeerView: MutablePostboxView { } if let peer = self.peers[self.peerId] { - if let associatedPeerId = peer.associatedPeerId { + if let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { if let (_, notificationSettings) = updatedNotificationSettings[associatedPeerId] { self.notificationSettings = notificationSettings updated = true diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 702394b8d0..cf1cca5917 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -3309,7 +3309,7 @@ final class PostboxImpl { additionalDataEntries.append(.totalUnreadState(self.messageHistoryMetadataTable.getTotalUnreadState(groupId: .root))) case let .peerNotificationSettings(peerId): var notificationPeerId = peerId - if let peer = self.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId { + if let peer = self.peerTable.get(peerId), let associatedPeerId = peer.associatedPeerId, peer.associatedPeerOverridesIdentity { notificationPeerId = associatedPeerId } additionalDataEntries.append(.peerNotificationSettings(self.peerNotificationSettingsTable.getEffective(notificationPeerId))) @@ -3319,7 +3319,7 @@ final class PostboxImpl { additionalDataEntries.append(.preferencesEntry(key, self.preferencesTable.get(key: key))) case let .peerIsContact(peerId): let value: Bool - if let contactPeer = self.peerTable.get(peerId), let associatedPeerId = contactPeer.associatedPeerId { + if let contactPeer = self.peerTable.get(peerId), contactPeer.associatedPeerOverridesIdentity, let associatedPeerId = contactPeer.associatedPeerId { value = self.contactsTable.isContact(peerId: associatedPeerId) } else { value = self.contactsTable.isContact(peerId: peerId) diff --git a/submodules/Postbox/Sources/SeedConfiguration.swift b/submodules/Postbox/Sources/SeedConfiguration.swift index 66e0d82094..260ee2b2c2 100644 --- a/submodules/Postbox/Sources/SeedConfiguration.swift +++ b/submodules/Postbox/Sources/SeedConfiguration.swift @@ -66,7 +66,7 @@ public final class SeedConfiguration { public let existingGlobalMessageTags: GlobalMessageTags public let peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace] public let peerSummaryCounterTags: (Peer, Bool) -> PeerSummaryCounterTags - public let peerSummaryIsThreadBased: (Peer) -> Bool + public let peerSummaryIsThreadBased: (Peer) -> (value: Bool, threadsArePeers: Bool) public let additionalChatListIndexNamespace: MessageId.Namespace? public let messageNamespacesRequiringGroupStatsValidation: Set public let defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState] @@ -97,7 +97,7 @@ public final class SeedConfiguration { existingGlobalMessageTags: GlobalMessageTags, peerNamespacesRequiringMessageTextIndex: [PeerId.Namespace], peerSummaryCounterTags: @escaping (Peer, Bool) -> PeerSummaryCounterTags, - peerSummaryIsThreadBased: @escaping (Peer) -> Bool, + peerSummaryIsThreadBased: @escaping (Peer) -> (value: Bool, threadsArePeers: Bool), additionalChatListIndexNamespace: MessageId.Namespace?, messageNamespacesRequiringGroupStatsValidation: Set, defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState], diff --git a/submodules/Postbox/Sources/UnreadMessageCountsView.swift b/submodules/Postbox/Sources/UnreadMessageCountsView.swift index 6818122a3b..988f23b9b4 100644 --- a/submodules/Postbox/Sources/UnreadMessageCountsView.swift +++ b/submodules/Postbox/Sources/UnreadMessageCountsView.swift @@ -64,7 +64,7 @@ final class MutableUnreadMessageCountsView: MutablePostboxView { case let .totalInGroup(groupId): return .totalInGroup(groupId, postbox.messageHistoryMetadataTable.getTotalUnreadState(groupId: groupId)) case let .peer(peerId, handleThreads): - if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { var count: Int32 = 0 if let summary = postbox.peerThreadsSummaryTable.get(peerId: peerId) { count = summary.totalUnreadCount @@ -113,7 +113,7 @@ final class MutableUnreadMessageCountsView: MutablePostboxView { } } case let .peer(peerId, handleThreads, _): - if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { if transaction.updatedPeerThreadsSummaries.contains(peerId) { var count: Int32 = 0 if let summary = postbox.peerThreadsSummaryTable.get(peerId: peerId) { @@ -143,7 +143,7 @@ final class MutableUnreadMessageCountsView: MutablePostboxView { case let .totalInGroup(groupId): return .totalInGroup(groupId, postbox.messageHistoryMetadataTable.getTotalUnreadState(groupId: groupId)) case let .peer(peerId, handleThreads): - if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { var count: Int32 = 0 if let summary = postbox.peerThreadsSummaryTable.get(peerId: peerId) { count = summary.totalUnreadCount @@ -240,7 +240,7 @@ final class MutableCombinedReadStateView: MutablePostboxView { var updated = false if transaction.alteredInitialPeerCombinedReadStates[self.peerId] != nil || transaction.updatedPeerThreadCombinedStates.contains(self.peerId) { - if self.handleThreads, let peer = postbox.peerTable.get(self.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if self.handleThreads, let peer = postbox.peerTable.get(self.peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { var count: Int32 = 0 if let summary = postbox.peerThreadsSummaryTable.get(peerId: peerId) { count = summary.totalUnreadCount @@ -260,7 +260,7 @@ final class MutableCombinedReadStateView: MutablePostboxView { func refreshDueToExternalTransaction(postbox: PostboxImpl) -> Bool { let state: CombinedPeerReadState? - if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer) { + if handleThreads, let peer = postbox.peerTable.get(peerId), postbox.seedConfiguration.peerSummaryIsThreadBased(peer).value { var count: Int32 = 0 if let summary = postbox.peerThreadsSummaryTable.get(peerId: peerId) { count = summary.totalUnreadCount diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index 865f85b9ff..bc5d8b6b3e 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -539,6 +539,7 @@ struct LoadMessageHistoryThreadsResult { var unreadMentionsCount: Int32 var unreadReactionsCount: Int32 var index: StoredPeerThreadCombinedState.Index? + var threadPeer: Peer? init( threadId: Int64, @@ -546,7 +547,8 @@ struct LoadMessageHistoryThreadsResult { topMessage: Int32, unreadMentionsCount: Int32, unreadReactionsCount: Int32, - index: StoredPeerThreadCombinedState.Index + index: StoredPeerThreadCombinedState.Index, + threadPeer: Peer? ) { self.threadId = threadId self.data = data @@ -554,6 +556,7 @@ struct LoadMessageHistoryThreadsResult { self.unreadMentionsCount = unreadMentionsCount self.unreadReactionsCount = unreadReactionsCount self.index = index + self.threadPeer = threadPeer } } @@ -661,7 +664,8 @@ public func _internal_fillSavedMessageHistory(accountPeerId: PeerId, postbox: Po topMessage: message.id.id, unreadMentionsCount: 0, unreadReactionsCount: 0, - index: StoredPeerThreadCombinedState.Index(timestamp: message.timestamp, threadId: threadId, messageId: message.id.id) + index: StoredPeerThreadCombinedState.Index(timestamp: message.timestamp, threadId: threadId, messageId: message.id.id), + threadPeer: nil )) } @@ -791,13 +795,22 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post minIndex = topicIndex } + var threadPeer: Peer? + for user in users { + if user.peerId == peer.peerId { + threadPeer = TelegramUser(user: user) + break + } + } + items.append(LoadMessageHistoryThreadsResult.Item( threadId: peer.peerId.toInt64(), data: data, topMessage: topMessage, unreadMentionsCount: 0, unreadReactionsCount: 0, - index: topicIndex + index: topicIndex, + threadPeer: threadPeer )) } } @@ -936,7 +949,8 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post topMessage: topMessage, unreadMentionsCount: unreadMentionsCount, unreadReactionsCount: unreadReactionsCount, - index: topicIndex + index: topicIndex, + threadPeer: nil )) case .forumTopicDeleted: break @@ -1157,7 +1171,8 @@ public func _internal_searchForumTopics(account: Account, peerId: EnginePeer.Id, iconFileId: itemData.info.icon, iconColor: itemData.info.iconColor, maxOutgoingReadMessageId: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: itemData.maxOutgoingReadId), - isUnread: false + isUnread: false, + threadPeer: item.threadPeer.flatMap(EnginePeer.init) ), topForumTopicItems: [], hasFailed: false, diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index ebb08aa4de..14dc6a371e 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -2336,7 +2336,7 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw var notificationPeerId = id.peerId let peer = transaction.getPeer(id.peerId) - if let peer = peer, let associatedPeerId = peer.associatedPeerId { + if let peer, peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } if message.personal, let author = message.author { diff --git a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift index 0bbbb360be..8d251c6422 100644 --- a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift @@ -93,7 +93,7 @@ func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: Pe return postbox.transaction { transaction -> Signal in if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index 5bb2814a5d..6521525367 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -946,9 +946,14 @@ public final class PendingMessageManager { } var topMsgId: Int32? + var monoforumPeerId: Api.InputPeer? if let threadId = messages[0].0.threadId { - flags |= Int32(1 << 9) - topMsgId = Int32(clamping: threadId) + if let channel = peer as? TelegramChannel, channel.flags.contains(.isMonoforum) { + monoforumPeerId = transaction.getPeer(PeerId(threadId)).flatMap(apiInputPeer) + } else { + flags |= Int32(1 << 9) + topMsgId = Int32(clamping: threadId) + } } var quickReplyShortcut: Api.InputQuickReplyShortcut? @@ -965,6 +970,12 @@ public final class PendingMessageManager { flags |= 1 << 21 } + var replyTo: Api.InputReplyTo? + if let monoforumPeerId { + replyTo = .inputReplyToMonoForum(monoforumPeerId: monoforumPeerId) + flags |= 1 << 22 + } + let forwardPeerIds = Set(forwardIds.map { $0.0.peerId }) if forwardPeerIds.count != 1 { assertionFailure() @@ -972,7 +983,7 @@ public final class PendingMessageManager { } else if let inputSourcePeerId = forwardPeerIds.first, let inputSourcePeer = transaction.getPeer(inputSourcePeerId).flatMap(apiInputPeer) { let dependencyTag = PendingMessageRequestDependencyTag(messageId: messages[0].0.id) - sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: inputSourcePeer, id: forwardIds.map { $0.0.id }, randomId: forwardIds.map { $0.1 }, toPeer: inputPeer, topMsgId: topMsgId, replyTo: nil, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, videoTimestamp: videoTimestamp, allowPaidStars: allowPaidStars), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: inputSourcePeer, id: forwardIds.map { $0.0.id }, randomId: forwardIds.map { $0.1 }, toPeer: inputPeer, topMsgId: topMsgId, replyTo: replyTo, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, videoTimestamp: videoTimestamp, allowPaidStars: allowPaidStars), tag: dependencyTag) } else { assertionFailure() sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "Invalid forward source")) @@ -1601,9 +1612,14 @@ public final class PendingMessageManager { |> map(NetworkRequestResult.result) case let .forward(sourceInfo): var topMsgId: Int32? + var monoforumPeerId: Api.InputPeer? if let threadId = message.threadId { - flags |= Int32(1 << 9) - topMsgId = Int32(clamping: threadId) + if let channel = peer as? TelegramChannel, channel.flags.contains(.isMonoforum) { + monoforumPeerId = transaction.getPeer(PeerId(threadId)).flatMap(apiInputPeer) + } else { + flags |= Int32(1 << 9) + topMsgId = Int32(clamping: threadId) + } } var quickReplyShortcut: Api.InputQuickReplyShortcut? @@ -1624,8 +1640,14 @@ public final class PendingMessageManager { flags |= 1 << 21 } + var replyTo: Api.InputReplyTo? + if let monoforumPeerId { + replyTo = .inputReplyToMonoForum(monoforumPeerId: monoforumPeerId) + flags |= 1 << 22 + } + if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) { - sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, replyTo: nil, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, videoTimestamp: videoTimestamp, allowPaidStars: allowPaidStars), tag: dependencyTag) + sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, replyTo: replyTo, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: quickReplyShortcut, videoTimestamp: videoTimestamp, allowPaidStars: allowPaidStars), tag: dependencyTag) |> map(NetworkRequestResult.result) } else { sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal")) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift index e77b74f5fa..d5af6a3b65 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift @@ -76,12 +76,14 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = { peerSummaryIsThreadBased: { peer in if let channel = peer as? TelegramChannel { if channel.flags.contains(.isForum) { - return true + return (true, false) + } else if channel.flags.contains(.isMonoforum) { + return (true, true) } else { - return false + return (false, false) } } else { - return false + return (false, false) } }, additionalChatListIndexNamespace: Namespaces.Message.Cloud, diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift index a9b229dbb3..e0488d04a1 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift @@ -214,6 +214,14 @@ public final class TelegramChannel: Peer, Equatable { public let sendPaidMessageStars: StarsAmount? public let linkedMonoforumId: PeerId? + public var associatedPeerId: PeerId? { + if self.flags.contains(.isMonoforum) { + return self.linkedMonoforumId + } else { + return nil + } + } + public var indexName: PeerIndexNameRepresentation { var addressNames = self.usernames.map { $0.username } if addressNames.isEmpty, let username = self.username, !username.isEmpty { @@ -245,7 +253,6 @@ public final class TelegramChannel: Peer, Equatable { return mediaIds } - public let associatedPeerId: PeerId? = nil public let notificationSettingsPeerId: PeerId? = nil public var timeoutAttribute: UInt32? { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramSecretChat.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramSecretChat.swift index be745fbed8..d1958c38ee 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramSecretChat.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramSecretChat.swift @@ -17,6 +17,10 @@ public final class TelegramSecretChat: Peer, Equatable { public var associatedMediaIds: [MediaId]? { return nil } public let associatedPeerId: PeerId? + public var associatedPeerControlsNotifications: Bool { + return true + } + public let notificationSettingsPeerId: PeerId? public var timeoutAttribute: UInt32? { return nil } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift index ab96357d77..a36e8fa7d8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift @@ -28,21 +28,48 @@ public final class EngineChatList: Equatable { } } - public struct ForumTopicData: Equatable { - public var id: Int64 - public var title: String - public var iconFileId: Int64? - public var iconColor: Int32 - public var maxOutgoingReadMessageId: EngineMessage.Id - public var isUnread: Bool + public final class ForumTopicData: Equatable { + public let id: Int64 + public let title: String + public let iconFileId: Int64? + public let iconColor: Int32 + public let maxOutgoingReadMessageId: EngineMessage.Id + public let isUnread: Bool + public let threadPeer: EnginePeer? - public init(id: Int64, title: String, iconFileId: Int64?, iconColor: Int32, maxOutgoingReadMessageId: EngineMessage.Id, isUnread: Bool) { + public init(id: Int64, title: String, iconFileId: Int64?, iconColor: Int32, maxOutgoingReadMessageId: EngineMessage.Id, isUnread: Bool, threadPeer: EnginePeer?) { self.id = id self.title = title self.iconFileId = iconFileId self.iconColor = iconColor self.maxOutgoingReadMessageId = maxOutgoingReadMessageId self.isUnread = isUnread + self.threadPeer = threadPeer + } + + public static func ==(lhs: ForumTopicData, rhs: ForumTopicData) -> Bool { + if lhs.id != rhs.id { + return false + } + if lhs.title != rhs.title { + return false + } + if lhs.iconFileId != rhs.iconFileId { + return false + } + if lhs.iconColor != rhs.iconColor { + return false + } + if lhs.maxOutgoingReadMessageId != rhs.maxOutgoingReadMessageId { + return false + } + if lhs.isUnread != rhs.isUnread { + return false + } + if lhs.threadPeer != rhs.threadPeer { + return false + } + return true } } @@ -507,15 +534,15 @@ extension EngineChatList.Item { var forumTopicDataValue: EngineChatList.ForumTopicData? if let forumTopicData = forumTopicData { let id = forumTopicData.id - if let forumTopicData = forumTopicData.info.data.get(MessageHistoryThreadData.self) { - forumTopicDataValue = EngineChatList.ForumTopicData(id: id, title: forumTopicData.info.title, iconFileId: forumTopicData.info.icon, iconColor: forumTopicData.info.iconColor, maxOutgoingReadMessageId: MessageId(peerId: index.messageIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: forumTopicData.maxOutgoingReadId), isUnread: forumTopicData.incomingUnreadCount > 0) + if let forumTopicInfo = forumTopicData.info.data.get(MessageHistoryThreadData.self) { + forumTopicDataValue = EngineChatList.ForumTopicData(id: id, title: forumTopicInfo.info.title, iconFileId: forumTopicInfo.info.icon, iconColor: forumTopicInfo.info.iconColor, maxOutgoingReadMessageId: MessageId(peerId: index.messageIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: forumTopicInfo.maxOutgoingReadId), isUnread: forumTopicInfo.incomingUnreadCount > 0, threadPeer: forumTopicData.threadPeer.flatMap(EnginePeer.init)) } } var topForumTopicItems: [EngineChatList.ForumTopicData] = [] for item in topForumTopics { - if let forumTopicData = item.info.data.get(MessageHistoryThreadData.self) { - topForumTopicItems.append(EngineChatList.ForumTopicData(id: item.id, title: forumTopicData.info.title, iconFileId: forumTopicData.info.icon, iconColor: forumTopicData.info.iconColor, maxOutgoingReadMessageId: MessageId(peerId: index.messageIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: forumTopicData.maxOutgoingReadId), isUnread: forumTopicData.incomingUnreadCount > 0)) + if let forumTopicInfo = item.info.data.get(MessageHistoryThreadData.self) { + topForumTopicItems.append(EngineChatList.ForumTopicData(id: item.id, title: forumTopicInfo.info.title, iconFileId: forumTopicInfo.info.icon, iconColor: forumTopicInfo.info.iconColor, maxOutgoingReadMessageId: MessageId(peerId: index.messageIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: forumTopicInfo.maxOutgoingReadId), isUnread: forumTopicInfo.incomingUnreadCount > 0, threadPeer: item.threadPeer.flatMap(EnginePeer.init))) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift index 384bd0f1b7..fe3110e357 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChangePeerNotificationSettings.swift @@ -10,7 +10,7 @@ func _internal_togglePeerMuted(account: Account, peerId: PeerId, threadId: Int64 } var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -91,7 +91,7 @@ func _internal_togglePeerStoriesMuted(account: Account, peerId: PeerId) -> Signa } var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -174,7 +174,7 @@ func _internal_updatePeerMuteSetting(account: Account, transaction: Transaction, } } else { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -232,7 +232,7 @@ func _internal_updatePeerDisplayPreviewsSetting(account: Account, transaction: T } } else { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -259,7 +259,7 @@ func _internal_updatePeerStoriesMutedSetting(account: Account, peerId: PeerId, m func _internal_updatePeerStoriesMutedSetting(account: Account, transaction: Transaction, peerId: PeerId, mute: PeerStoryNotificationSettings.Mute) { if let peer = transaction.getPeer(peerId) { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -281,7 +281,7 @@ func _internal_updatePeerStoriesMutedSetting(account: Account, transaction: Tran func _internal_updatePeerStoriesHideSenderSetting(account: Account, transaction: Transaction, peerId: PeerId, hideSender: PeerStoryNotificationSettings.HideSender) { if let peer = transaction.getPeer(peerId) { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -323,7 +323,7 @@ func _internal_updatePeerNotificationSoundInteractive(account: Account, transact } } else { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } @@ -344,7 +344,7 @@ func _internal_updatePeerNotificationSoundInteractive(account: Account, transact func _internal_updatePeerStoryNotificationSoundInteractive(account: Account, transaction: Transaction, peerId: PeerId, sound: PeerMessageSound) { if let peer = transaction.getPeer(peerId) { var notificationPeerId = peerId - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { notificationPeerId = associatedPeerId } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift index b03f6347e6..b87b061470 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift @@ -632,6 +632,14 @@ public final class EngineRenderedPeer: Equatable { return nil } } + + public var chatOrMonoforumMainPeer: EnginePeer? { + if case let .channel(channel) = self.peer, channel.flags.contains(.isMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + return self.peers[linkedMonoforumId] + } else { + return self.chatMainPeer + } + } } public extension EngineRenderedPeer { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift index a882113c10..f3a600ee9d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RecentlySearchedPeerIds.swift @@ -80,7 +80,7 @@ public func _internal_recentlySearchedPeers(postbox: Postbox) -> Signal<[Recentl var presence: TelegramUserPresence? var unreadCount = unreadCounts[peerId] ?? 0 if let peer = peerView.peers[peerId] { - if let associatedPeerId = peer.associatedPeerId { + if peer is TelegramSecretChat, let associatedPeerId = peer.associatedPeerId { presence = peerView.peerPresences[associatedPeerId] as? TelegramUserPresence } else { presence = peerView.peerPresences[peerId] as? TelegramUserPresence diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift index de39e91f77..c7c38cb20b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift @@ -895,243 +895,6 @@ func _internal_collectCacheUsageStats(account: Account, peerId: PeerId? = nil, a } |> runOn(queue) } - - /*let initialState = CacheUsageStatsState() - if let peerId = peerId { - initialState.lowerBound = MessageIndex.lowerBound(peerId: peerId) - initialState.upperBound = MessageIndex.upperBound(peerId: peerId) - } - - let state = Atomic(value: initialState) - - let excludeResourceIds = account.postbox.transaction { transaction -> Set in - var result = Set() - transaction.enumeratePreferencesEntries({ entry in - result.formUnion(entry.relatedResources) - return true - }) - return result - } - - return excludeResourceIds - |> mapToSignal { excludeResourceIds -> Signal in - let fetch = account.postbox.transaction { transaction -> ([PeerId : Set], [MediaId : Media], MessageIndex?) in - return transaction.enumerateMedia(lowerBound: state.with { $0.lowerBound }, upperBound: state.with { $0.upperBound }, limit: 1000) - } - |> mapError { _ -> CollectCacheUsageStatsError in } - - let process: ([PeerId : Set], [MediaId : Media], MessageIndex?) -> Signal = { mediaByPeer, mediaRefs, updatedLowerBound in - var mediaIdToPeerId: [MediaId: PeerId] = [:] - for (peerId, mediaIds) in mediaByPeer { - for id in mediaIds { - mediaIdToPeerId[id] = peerId - } - } - - var resourceIdToMediaId: [MediaResourceId: (MediaId, PeerCacheUsageCategory)] = [:] - var mediaResourceIds: [MediaId: [MediaResourceId]] = [:] - var resourceIds: [MediaResourceId] = [] - for (id, media) in mediaRefs { - mediaResourceIds[id] = [] - var parsedMedia: [Media] = [] - switch media { - case let image as TelegramMediaImage: - parsedMedia.append(image) - case let file as TelegramMediaFile: - parsedMedia.append(file) - case let webpage as TelegramMediaWebpage: - if case let .Loaded(content) = webpage.content { - if let image = content.image { - parsedMedia.append(image) - } - if let file = content.file { - parsedMedia.append(file) - } - } - default: - break - } - for media in parsedMedia { - if let image = media as? TelegramMediaImage { - for representation in image.representations { - resourceIds.append(representation.resource.id) - resourceIdToMediaId[representation.resource.id] = (id, .image) - mediaResourceIds[id]!.append(representation.resource.id) - } - } else if let file = media as? TelegramMediaFile { - var category: PeerCacheUsageCategory = .file - loop: for attribute in file.attributes { - switch attribute { - case .Video: - category = .video - break loop - case .Audio: - category = .audio - break loop - default: - break - } - } - for representation in file.previewRepresentations { - resourceIds.append(representation.resource.id) - resourceIdToMediaId[representation.resource.id] = (id, category) - mediaResourceIds[id]!.append(representation.resource.id) - } - resourceIds.append(file.resource.id) - resourceIdToMediaId[file.resource.id] = (id, category) - mediaResourceIds[id]!.append(file.resource.id) - } - } - } - return account.postbox.mediaBox.collectResourceCacheUsage(resourceIds) - |> mapError { _ -> CollectCacheUsageStatsError in } - |> mapToSignal { result -> Signal in - state.with { state -> Void in - state.lowerBound = updatedLowerBound - for (wrappedId, size) in result { - if let (id, category) = resourceIdToMediaId[wrappedId] { - if let peerId = mediaIdToPeerId[id] { - if state.media[peerId] == nil { - state.media[peerId] = [:] - } - if state.media[peerId]![category] == nil { - state.media[peerId]![category] = [:] - } - var currentSize: Int64 = 0 - if let current = state.media[peerId]![category]![id] { - currentSize = current - } - state.media[peerId]![category]![id] = currentSize + size - } - } - } - for (id, ids) in mediaResourceIds { - state.mediaResourceIds[id] = ids - for resourceId in ids { - state.allResourceIds.insert(resourceId) - } - } - } - if updatedLowerBound == nil { - if peerId != nil { - let (finalMedia, finalMediaResourceIds, _) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set) in - return (state.media, state.mediaResourceIds, state.allResourceIds) - } - return account.postbox.transaction { transaction -> CacheUsageStats in - var peers: [PeerId: Peer] = [:] - for peerId in finalMedia.keys { - if let peer = transaction.getPeer(peerId) { - peers[peer.id] = peer - if let associatedPeerId = peer.associatedPeerId, let associatedPeer = transaction.getPeer(associatedPeerId) { - peers[associatedPeer.id] = associatedPeer - } - } - } - return CacheUsageStats(media: finalMedia, mediaResourceIds: finalMediaResourceIds, peers: peers, otherSize: 0, otherPaths: [], cacheSize: 0, tempPaths: [], tempSize: 0, immutableSize: 0) - } |> mapError { _ -> CollectCacheUsageStatsError in } - |> mapToSignal { stats -> Signal in - return .fail(.done(stats)) - } - } - - let (finalMedia, finalMediaResourceIds, allResourceIds) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set) in - return (state.media, state.mediaResourceIds, state.allResourceIds) - } - - return account.postbox.mediaBox.collectOtherResourceUsage(excludeIds: excludeResourceIds, combinedExcludeIds: allResourceIds.union(excludeResourceIds)) - |> mapError { _ -> CollectCacheUsageStatsError in } - |> mapToSignal { otherSize, otherPaths, cacheSize in - var tempPaths: [String] = [] - var tempSize: Int64 = 0 - #if os(iOS) - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: NSTemporaryDirectory()), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { - for url in enumerator { - if let url = url as? URL { - if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { - tempPaths.append(url.path) - } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { - tempPaths.append(url.path) - - if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { - } else { - tempSize += Int64(fileSizeValue) - } - } - } - } - } - #endif - - var immutableSize: Int64 = 0 - if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: account.basePath + "/postbox/db"), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { - for url in files { - if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { - immutableSize += Int64(fileSize) - } - } - } - if let logFilesPath = logFilesPath, let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logFilesPath), includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: []) { - for url in files { - if let fileSize = (try? url.resourceValues(forKeys: Set([.fileSizeKey])))?.fileSize { - immutableSize += Int64(fileSize) - } - } - } - - for additionalPath in additionalCachePaths { - if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: additionalPath), includingPropertiesForKeys: [.isDirectoryKey, .fileAllocatedSizeKey, .isSymbolicLinkKey]) { - for url in enumerator { - if let url = url as? URL { - if let isDirectoryValue = (try? url.resourceValues(forKeys: Set([.isDirectoryKey])))?.isDirectory, isDirectoryValue { - } else if let fileSizeValue = (try? url.resourceValues(forKeys: Set([.fileAllocatedSizeKey])))?.fileAllocatedSize { - tempPaths.append(url.path) - - if let isSymbolicLinkValue = (try? url.resourceValues(forKeys: Set([.isSymbolicLinkKey])))?.isSymbolicLink, isSymbolicLinkValue { - } else { - tempSize += Int64(fileSizeValue) - } - } - } - } - } - } - - return account.postbox.transaction { transaction -> CacheUsageStats in - var peers: [PeerId: Peer] = [:] - for peerId in finalMedia.keys { - if let peer = transaction.getPeer(peerId) { - peers[peer.id] = peer - if let associatedPeerId = peer.associatedPeerId, let associatedPeer = transaction.getPeer(associatedPeerId) { - peers[associatedPeer.id] = associatedPeer - } - } - } - return CacheUsageStats(media: finalMedia, mediaResourceIds: finalMediaResourceIds, peers: peers, otherSize: otherSize, otherPaths: otherPaths, cacheSize: cacheSize, tempPaths: tempPaths, tempSize: tempSize, immutableSize: immutableSize) - } |> mapError { _ -> CollectCacheUsageStatsError in } - |> mapToSignal { stats -> Signal in - return .fail(.done(stats)) - } - } - } else { - return .complete() - } - } - } - - let signal = (fetch |> mapToSignal { mediaByPeer, mediaRefs, updatedLowerBound -> Signal in - return process(mediaByPeer, mediaRefs, updatedLowerBound) - }) - |> restart - - return signal |> `catch` { error in - switch error { - case let .done(result): - return .single(.result(result)) - case .generic: - return .complete() - } - } - }*/ } func _internal_clearCachedMediaResources(account: Account, mediaResourceIds: Set) -> Signal { diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index f2fcf59926..d220929f38 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -481,6 +481,14 @@ public extension RenderedPeer { return nil } } + + var chatOrMonoforumMainPeer: Peer? { + if let channel = self.peer as? TelegramChannel, channel.flags.contains(.isMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + return self.peers[linkedMonoforumId] + } else { + return self.chatMainPeer + } + } } public func isServicePeer(_ peer: Peer) -> Bool { diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index 3e628f8d9f..20fa49182c 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -403,17 +403,49 @@ public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePee } public func chatControllerForForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64) -> Signal { - return fetchAndPreloadReplyThreadInfo(context: context, subject: .groupMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))), atMessageId: nil, preload: false) + return context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) + ) |> deliverOnMainQueue - |> `catch` { _ -> Signal in - return .complete() - } - |> map { result in - return ChatControllerImpl( - context: context, - chatLocation: .replyThread(message: result.message), - chatLocationContextHolder: result.contextHolder - ) + |> mapToSignal { peer -> Signal in + guard let peer else { + return .complete() + } + + if case let .channel(channel) = peer, channel.flags.contains(.isMonoforum) { + return .single(ChatControllerImpl( + context: context, + chatLocation: .replyThread(message: ChatReplyThreadMessage( + peerId: peer.id, + threadId: threadId, + channelMessageId: nil, + isChannelPost: false, + isForumPost: true, + isMonoforumPost: channel.flags.contains(.isMonoforum), + maxMessage: nil, + maxReadIncomingMessageId: nil, + maxReadOutgoingMessageId: nil, + unreadCount: 0, + initialFilledHoles: IndexSet(), + initialAnchor: .automatic, + isNotAvailable: false + )), + chatLocationContextHolder: Atomic(value: nil) + )) + } else { + return fetchAndPreloadReplyThreadInfo(context: context, subject: .groupMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId))), atMessageId: nil, preload: false) + |> deliverOnMainQueue + |> `catch` { _ -> Signal in + return .complete() + } + |> map { result in + return ChatControllerImpl( + context: context, + chatLocation: .replyThread(message: result.message), + chatLocationContextHolder: result.contextHolder + ) + } + } } }