[WIP] Monoforums

This commit is contained in:
Isaac 2025-05-16 01:02:25 +08:00
parent b752a49432
commit 1a56afcb48
28 changed files with 426 additions and 403 deletions

View File

@ -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
}
}

View File

@ -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<Empty>
var titleTopicIconComponent: EmojiStatusComponent
let titleTopicIconView: ComponentHostView<Empty>?
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<Empty>, titleTopicIconComponent: EmojiStatusComponent) {
private init(topicTitleNode: TextNode, titleTopicIconView: ComponentHostView<Empty>?, 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<Empty>
if let current = currentNode?.titleTopicIconView {
titleTopicIconView = current
} else {
titleTopicIconView = ComponentHostView<Empty>()
}
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<Empty>?
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<Empty>()
}
}
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)
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)
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

View File

@ -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,

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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) {

View File

@ -48,7 +48,7 @@ final class MutablePeerView: MutablePostboxView {
var messageIds = Set<MessageId>()
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

View File

@ -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)

View File

@ -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<MessageId.Namespace>
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<MessageId.Namespace>,
defaultMessageNamespaceReadStates: [MessageId.Namespace: PeerReadState],

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -93,7 +93,7 @@ func pushPeerNotificationSettings(postbox: Postbox, network: Network, peerId: Pe
return postbox.transaction { transaction -> Signal<Void, NoError> 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
}

View File

@ -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"))

View File

@ -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,

View File

@ -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? {

View File

@ -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 }

View File

@ -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)))
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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<CacheUsageStatsState>(value: initialState)
let excludeResourceIds = account.postbox.transaction { transaction -> Set<MediaResourceId> in
var result = Set<MediaResourceId>()
transaction.enumeratePreferencesEntries({ entry in
result.formUnion(entry.relatedResources)
return true
})
return result
}
return excludeResourceIds
|> mapToSignal { excludeResourceIds -> Signal<CacheUsageStatsResult, NoError> in
let fetch = account.postbox.transaction { transaction -> ([PeerId : Set<MediaId>], [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>], [MediaId : Media], MessageIndex?) -> Signal<CacheUsageStatsResult, CollectCacheUsageStatsError> = { 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<CacheUsageStatsResult, CollectCacheUsageStatsError> 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<MediaResourceId>) 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<CacheUsageStatsResult, CollectCacheUsageStatsError> in
return .fail(.done(stats))
}
}
let (finalMedia, finalMediaResourceIds, allResourceIds) = state.with { state -> ([PeerId: [PeerCacheUsageCategory: [MediaId: Int64]]], [MediaId: [MediaResourceId]], Set<MediaResourceId>) 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<CacheUsageStatsResult, CollectCacheUsageStatsError> in
return .fail(.done(stats))
}
}
} else {
return .complete()
}
}
}
let signal = (fetch |> mapToSignal { mediaByPeer, mediaRefs, updatedLowerBound -> Signal<CacheUsageStatsResult, CollectCacheUsageStatsError> 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<MediaResourceId>) -> Signal<Float, NoError> {

View File

@ -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 {

View File

@ -403,17 +403,49 @@ public func navigateToForumThreadImpl(context: AccountContext, peerId: EnginePee
}
public func chatControllerForForumThreadImpl(context: AccountContext, peerId: EnginePeer.Id, threadId: Int64) -> Signal<ChatController, NoError> {
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<ReplyThreadInfo, NoError> in
return .complete()
}
|> map { result in
return ChatControllerImpl(
context: context,
chatLocation: .replyThread(message: result.message),
chatLocationContextHolder: result.contextHolder
)
|> mapToSignal { peer -> Signal<ChatController, NoError> 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<ReplyThreadInfo, NoError> in
return .complete()
}
|> map { result in
return ChatControllerImpl(
context: context,
chatLocation: .replyThread(message: result.message),
chatLocationContextHolder: result.contextHolder
)
}
}
}
}