diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 137d236ee8..30b0ec57da 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -183,6 +183,7 @@ struct AccountMutableState { var state: AuthorizedAccountState.State var peers: [PeerId: Peer] + var apiChats: [PeerId: Api.Chat] var channelStates: [PeerId: AccountStateChannelState] var peerChatInfos: [PeerId: PeerChatInfo] var referencedReplyMessageIds: ReferencedReplyMessageIds @@ -213,6 +214,7 @@ struct AccountMutableState { self.initialState = initialState self.state = initialState.state self.peers = initialPeers + self.apiChats = [:] self.referencedReplyMessageIds = initialReferencedReplyMessageIds self.referencedGeneralMessageIds = initialReferencedGeneralMessageIds self.storedMessages = initialStoredMessages @@ -225,11 +227,12 @@ struct AccountMutableState { self.updatedOutgoingUniqueMessageIds = [:] } - init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedReplyMessageIds: ReferencedReplyMessageIds, referencedGeneralMessageIds: Set, storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], dismissBotWebViews: [Int64], branchOperationIndex: Int) { + init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], apiChats: [PeerId: Api.Chat], channelStates: [PeerId: AccountStateChannelState], peerChatInfos: [PeerId: PeerChatInfo], referencedReplyMessageIds: ReferencedReplyMessageIds, referencedGeneralMessageIds: Set, storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: [MessageId.Namespace: HoleFromPreviousState]], updatedOutgoingUniqueMessageIds: [Int64: Int32], displayAlerts: [(text: String, isDropAuth: Bool)], dismissBotWebViews: [Int64], branchOperationIndex: Int) { self.initialState = initialState self.operations = operations self.state = state self.peers = peers + self.apiChats = apiChats self.channelStates = channelStates self.referencedReplyMessageIds = referencedReplyMessageIds self.referencedGeneralMessageIds = referencedGeneralMessageIds @@ -245,7 +248,7 @@ struct AccountMutableState { } func branch() -> AccountMutableState { - return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, channelStates: self.channelStates, peerChatInfos: self.peerChatInfos, referencedReplyMessageIds: self.referencedReplyMessageIds, referencedGeneralMessageIds: self.referencedGeneralMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, updatedOutgoingUniqueMessageIds: self.updatedOutgoingUniqueMessageIds, displayAlerts: self.displayAlerts, dismissBotWebViews: self.dismissBotWebViews, branchOperationIndex: self.operations.count) + return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, apiChats: self.apiChats, channelStates: self.channelStates, peerChatInfos: self.peerChatInfos, referencedReplyMessageIds: self.referencedReplyMessageIds, referencedGeneralMessageIds: self.referencedGeneralMessageIds, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, updatedOutgoingUniqueMessageIds: self.updatedOutgoingUniqueMessageIds, displayAlerts: self.displayAlerts, dismissBotWebViews: self.dismissBotWebViews, branchOperationIndex: self.operations.count) } mutating func merge(_ other: AccountMutableState) { @@ -258,6 +261,9 @@ struct AccountMutableState { for (_, peer) in other.insertedPeers { self.peers[peer.id] = peer } + for (_, chat) in other.apiChats { + self.apiChats[chat.peerId] = chat + } self.preCachedResources.append(contentsOf: other.preCachedResources) self.externallyUpdatedPeerId.formUnion(other.externallyUpdatedPeerId) for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState { @@ -410,8 +416,26 @@ struct AccountMutableState { } } + func isPeerForum(peerId: PeerId) -> Bool { + if let peer = self.peers[peerId] { + return peer.isForum + } else if let chat = self.apiChats[peerId] { + if let channel = parseTelegramGroupOrChannel(chat: chat) { + return channel.isForum + } else { + return false + } + } else { + Logger.shared.log("AccountIntermediateState", "isPeerForum undefinded for \(peerId)") + return false + } + } + mutating func mergeChats(_ chats: [Api.Chat]) { self.addOperation(.MergeApiChats(chats)) + for chat in chats { + self.apiChats[chat.peerId] = chat + } for chat in chats { switch chat { diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 6551558d83..73c596b5fa 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -418,7 +418,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes } extension StoreMessage { - convenience init?(apiMessage: Api.Message, namespace: MessageId.Namespace = Namespaces.Message.Cloud) { + convenience init?(apiMessage: Api.Message, peerIsForum: Bool, namespace: MessageId.Namespace = Namespaces.Message.Cloud) { switch apiMessage { case let .message(flags, id, fromId, chatPeerId, fwdFrom, viaBotId, replyTo, date, message, media, replyMarkup, entities, views, forwards, replies, editDate, postAuthor, groupingId, reactions, restrictionReason, ttlPeriod): let resolvedFromId = fromId?.peerId ?? chatPeerId.peerId @@ -443,7 +443,9 @@ extension StoreMessage { if let replyTo = replyTo { var threadMessageId: MessageId? switch replyTo { - case let .messageReplyHeader(_, replyToMsgId, replyToPeerId, replyToTopId): + case let .messageReplyHeader(flags, replyToMsgId, replyToPeerId, replyToTopId): + let isForumTopic = (flags & (1 << 3)) != 0 + let replyPeerId = replyToPeerId?.peerId ?? peerId if let replyToTopId = replyToTopId { let threadIdValue = MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToTopId) @@ -453,8 +455,16 @@ extension StoreMessage { } } else if peerId.namespace == Namespaces.Peer.CloudChannel { let threadIdValue = MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId) - threadMessageId = threadIdValue - threadId = makeMessageThreadId(threadIdValue) + + if peerIsForum { + if isForumTopic { + threadMessageId = threadIdValue + threadId = makeMessageThreadId(threadIdValue) + } + } else { + threadMessageId = threadIdValue + threadId = makeMessageThreadId(threadIdValue) + } } attributes.append(ReplyMessageAttribute(messageId: MessageId(peerId: replyPeerId, namespace: Namespaces.Message.Cloud, id: replyToMsgId), threadMessageId: threadMessageId)) } diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index 5aca44d338..5a0c0463f6 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -188,12 +188,15 @@ public enum CreateForumChannelTopicError { } func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title: String, iconColor: Int32, iconFileId: Int64?) -> Signal { - return account.postbox.transaction { transaction -> Api.InputChannel? in - return transaction.getPeer(peerId).flatMap(apiInputChannel) + return account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) } |> castError(CreateForumChannelTopicError.self) - |> mapToSignal { inputChannel -> Signal in - guard let inputChannel = inputChannel else { + |> mapToSignal { peer -> Signal in + guard let peer else { + return .fail(.generic) + } + guard let inputChannel = apiInputChannel(peer) else { return .fail(.generic) } var flags: Int32 = 0 @@ -221,7 +224,7 @@ func _internal_createForumChannelTopic(account: Account, peerId: PeerId, title: for update in result.allUpdates { switch update { case let .updateNewChannelMessage(message, _, _): - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { if case let .Id(id) = message.id { topicId = Int64(id.id) } @@ -605,7 +608,7 @@ func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Post var pinnedIds: [Int64] = [] let addedMessages = messages.compactMap { message -> StoreMessage? in - return StoreMessage(apiMessage: message) + return StoreMessage(apiMessage: message, peerIsForum: true) } let _ = pts diff --git a/submodules/TelegramCore/Sources/MacOS/MacInternalUpdater.swift b/submodules/TelegramCore/Sources/MacOS/MacInternalUpdater.swift index 2f935c149d..92b139dffe 100644 --- a/submodules/TelegramCore/Sources/MacOS/MacInternalUpdater.swift +++ b/submodules/TelegramCore/Sources/MacOS/MacInternalUpdater.swift @@ -25,7 +25,7 @@ public func requestUpdatesXml(account: Account, source: String) -> Signal mapToSignal { result in switch result { case let .channelMessages(_, _, _, _, apiMessages, _, apiChats, apiUsers): - if let apiMessage = apiMessages.first, let storeMessage = StoreMessage(apiMessage: apiMessage) { + if let apiMessage = apiMessages.first, let storeMessage = StoreMessage(apiMessage: apiMessage, peerIsForum: peer.isForum) { var peers: [PeerId: Peer] = [:] for chat in apiChats { @@ -103,7 +103,7 @@ public func downloadAppUpdate(account: Account, source: String, messageId: Int32 } let messageAndFile:(Message, TelegramMediaFile)? = apiMessages.compactMap { value in - return StoreMessage(apiMessage: value) + return StoreMessage(apiMessage: value, peerIsForum: peer.isForum) }.compactMap { value in return locallyRenderedMessage(message: value, peers: peers) }.sorted(by: { diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index 1ba5e1e043..529ce2b8f3 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -191,7 +191,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat if let result = result { return postbox.transaction { transaction -> RequestEditMessageResult in var toMedia: Media? - if let message = result.messages.first.flatMap({ StoreMessage(apiMessage: $0) }) { + if let message = result.messages.first.flatMap({ StoreMessage(apiMessage: $0, peerIsForum: peer.isForum) }) { toMedia = message.media.first } @@ -217,7 +217,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat updatePeers(transaction: transaction, peers: peers, update: { _, updated in updated }) - if let message = StoreMessage(apiMessage: message), case let .Id(id) = message.id { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), case let .Id(id) = message.id { transaction.updateMessage(id, update: { previousMessage in var updatedFlags = message.flags var updatedLocalTags = message.localTags diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 3c4519bfd1..35ba9e0383 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -713,7 +713,11 @@ func finalStateWithDifference(accountPeerId: PeerId, postbox: Postbox, network: updatedState.addPreCachedResource(resource, data: data) } } - if let message = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { updatedState.addMessages([message], location: .UpperHistoryBlock) } } @@ -917,7 +921,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } } case let .updateEditChannelMessage(apiMessage, pts, ptsCount): - if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id { + var peerIsForum = false + if let peerId = apiMessage.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum), case let .Id(messageId) = message.id { let peerId = messageId.peerId if let previousState = updatedState.channelStates[peerId] { if previousState.pts >= pts { @@ -984,7 +992,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id) }, pinned: (flags & (1 << 0)) != 0) case let .updateEditMessage(apiMessage, _, _): - if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id { + var peerIsForum = false + if let peerId = apiMessage.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum), case let .Id(messageId) = message.id { if let preCachedResources = apiMessage.preCachedResources { for (resource, data) in preCachedResources { updatedState.addPreCachedResource(resource, data: data) @@ -1000,7 +1012,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } } case let .updateNewChannelMessage(apiMessage, pts, ptsCount): - if let message = StoreMessage(apiMessage: apiMessage) { + var peerIsForum = false + if let peerId = apiMessage.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum) { if let previousState = updatedState.channelStates[message.id.peerId] { if previousState.pts >= pts { let messageText: String @@ -1038,7 +1054,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } } case let .updateNewMessage(apiMessage, _, _): - if let message = StoreMessage(apiMessage: apiMessage) { + var peerIsForum = false + if let peerId = apiMessage.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum) { if let preCachedResources = apiMessage.preCachedResources { for (resource, data) in preCachedResources { updatedState.addPreCachedResource(resource, data: data) @@ -1510,7 +1530,11 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } updatedState.updatePeersNearby(peersNearby) case let .updateNewScheduledMessage(apiMessage): - if let message = StoreMessage(apiMessage: apiMessage, namespace: Namespaces.Message.ScheduledCloud) { + var peerIsForum = false + if let peerId = apiMessage.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum, namespace: Namespaces.Message.ScheduledCloud) { updatedState.addScheduledMessages([message]) } case let .updateDeleteScheduledMessages(peer, messages): @@ -1703,17 +1727,17 @@ func resolveForumThreads(postbox: Postbox, network: Network, state: AccountMutab if missingForumThreadIds.isEmpty { return .single(state) } else { - var signals: [Signal<(PeerId, Api.messages.ForumTopics)?, NoError>] = [] + var signals: [Signal<(Peer, Api.messages.ForumTopics)?, NoError>] = [] for (peerId, threadIds) in missingForumThreadIds { - guard let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) else { + guard let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) else { Logger.shared.log("State", "can't fetch thread infos \(threadIds) for peer \(peerId): can't create inputChannel") continue } let signal = network.request(Api.functions.channels.getForumTopicsByID(channel: inputChannel, topics: threadIds)) - |> map { result -> (PeerId, Api.messages.ForumTopics)? in - return (peerId, result) + |> map { result -> (Peer, Api.messages.ForumTopics)? in + return (peer, result) } - |> `catch` { _ -> Signal<(PeerId, Api.messages.ForumTopics)?, NoError> in + |> `catch` { _ -> Signal<(Peer, Api.messages.ForumTopics)?, NoError> in return .single(nil) } signals.append(signal) @@ -1726,14 +1750,17 @@ func resolveForumThreads(postbox: Postbox, network: Network, state: AccountMutab var storeMessages: [StoreMessage] = [] for maybeResult in results { - if let (peerId, result) = maybeResult { + if let (peer, result) = maybeResult { + let peerIsForum = peer.isForum + let peerId = peer.id + switch result { case let .forumTopics(_, _, topics, messages, chats, users, pts): state.mergeChats(chats) state.mergeUsers(users) for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { storeMessages.append(message) } } @@ -1805,17 +1832,17 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) - if missingForumThreadIds.isEmpty { return .single(Void()) } else { - var signals: [Signal<(PeerId, Api.messages.ForumTopics)?, NoError>] = [] + var signals: [Signal<(Peer, Api.messages.ForumTopics)?, NoError>] = [] for (peerId, threadIds) in missingForumThreadIds { - guard let inputChannel = transaction.getPeer(peerId).flatMap(apiInputChannel) else { + guard let peer = transaction.getPeer(peerId), let inputChannel = apiInputChannel(peer) else { Logger.shared.log("State", "can't fetch thread infos \(threadIds) for peer \(peerId): can't create inputChannel") continue } let signal = network.request(Api.functions.channels.getForumTopicsByID(channel: inputChannel, topics: threadIds)) - |> map { result -> (PeerId, Api.messages.ForumTopics)? in - return (peerId, result) + |> map { result -> (Peer, Api.messages.ForumTopics)? in + return (peer, result) } - |> `catch` { _ -> Signal<(PeerId, Api.messages.ForumTopics)?, NoError> in + |> `catch` { _ -> Signal<(Peer, Api.messages.ForumTopics)?, NoError> in return .single(nil) } signals.append(signal) @@ -1829,14 +1856,17 @@ func resolveForumThreads(postbox: Postbox, network: Network, ids: [MessageId]) - var storeMessages: [StoreMessage] = [] for maybeResult in results { - if let (peerId, result) = maybeResult { + if let (peer, result) = maybeResult { + let peerIsForum = peer.isForum + let peerId = peer.id + switch result { case let .forumTopics(_, _, topics, messages, apiChats, apiUsers, _): chats.append(contentsOf: apiChats) users.append(contentsOf: apiUsers) for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { storeMessages.append(message) } } @@ -1927,17 +1957,17 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe if missingForumThreadIds.isEmpty { return .single(fetchedChatList) } else { - var signals: [Signal<(PeerId, Api.messages.ForumTopics)?, NoError>] = [] + var signals: [Signal<(Peer, Api.messages.ForumTopics)?, NoError>] = [] for (peerId, threadIds) in missingForumThreadIds { - guard let inputChannel = fetchedChatList.peers.first(where: { $0.id == peerId }).flatMap(apiInputChannel) else { + guard let peer = fetchedChatList.peers.first(where: { $0.id == peerId }), let inputChannel = apiInputChannel(peer) else { Logger.shared.log("resolveForumThreads", "can't fetch thread infos \(threadIds) for peer \(peerId): can't create inputChannel") continue } let signal = network.request(Api.functions.channels.getForumTopicsByID(channel: inputChannel, topics: threadIds)) - |> map { result -> (PeerId, Api.messages.ForumTopics)? in - return (peerId, result) + |> map { result -> (Peer, Api.messages.ForumTopics)? in + return (peer, result) } - |> `catch` { _ -> Signal<(PeerId, Api.messages.ForumTopics)?, NoError> in + |> `catch` { _ -> Signal<(Peer, Api.messages.ForumTopics)?, NoError> in return .single(nil) } signals.append(signal) @@ -1948,7 +1978,10 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe var fetchedChatList = fetchedChatList for maybeResult in results { - if let (peerId, result) = maybeResult { + if let (peer, result) = maybeResult { + let peerIsForum = peer.isForum + let peerId = peer.id + switch result { case let .forumTopics(_, _, topics, messages, chats, users, _): fetchedChatList.peers.append(contentsOf: chats.compactMap { chat in @@ -1959,7 +1992,7 @@ func resolveForumThreads(postbox: Postbox, network: Network, fetchedChatList: Fe }) for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { fetchedChatList.storeMessages.append(message) } } @@ -2141,21 +2174,26 @@ private func resolveAssociatedMessages(postbox: Postbox, network: Network, state |> map { results in var updatedState = state for (messages, chats, users) in results { - if !messages.isEmpty { - var storeMessages: [StoreMessage] = [] - for message in messages { - if let message = StoreMessage(apiMessage: message) { - storeMessages.append(message) - } - } - updatedState.addMessages(storeMessages, location: .Random) - } if !chats.isEmpty { updatedState.mergeChats(chats) } if !users.isEmpty { updatedState.mergeUsers(users) } + + if !messages.isEmpty { + var storeMessages: [StoreMessage] = [] + for message in messages { + var peerIsForum = false + if let peerId = message.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { + storeMessages.append(message) + } + } + updatedState.addMessages(storeMessages, location: .Random) + } } return updatedState } @@ -2272,7 +2310,11 @@ private func resolveMissingPeerChatInfos(network: Network, state: AccountMutable var storeMessages: [StoreMessage] = [] for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { var updatedStoreMessage = storeMessage if case let .Id(id) = storeMessage.id { if let channelState = channelStates[id.peerId] { @@ -2501,7 +2543,11 @@ private func resetChannels(accountPeerId: PeerId, postbox: Postbox, network: Net } for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId { + peerIsForum = updatedState.isPeerForum(peerId: peerId) + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { var updatedStoreMessage = storeMessage if case let .Id(id) = storeMessage.id { if let channelState = channelStates[id.peerId] { @@ -2645,7 +2691,11 @@ private func pollChannel(accountPeerId: PeerId, postbox: Postbox, network: Netwo var forumThreadIds = Set() for apiMessage in newMessages { - if var message = StoreMessage(apiMessage: apiMessage) { + var peerIsForum = peer.isForum + if let peerId = apiMessage.peerId, updatedState.isPeerForum(peerId: peerId) { + peerIsForum = true + } + if var message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum) { var attributes = message.attributes attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) message = message.withUpdatedAttributes(attributes) @@ -2674,7 +2724,11 @@ private func pollChannel(accountPeerId: PeerId, postbox: Postbox, network: Netwo let peerId = peer.id updatedState.deleteMessages(messages.map({ MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) })) case let .updateEditChannelMessage(apiMessage, _, _): - if let message = StoreMessage(apiMessage: apiMessage), case let .Id(messageId) = message.id, messageId.peerId == peer.id { + var peerIsForum = peer.isForum + if let peerId = apiMessage.peerId, updatedState.isPeerForum(peerId: peerId) { + peerIsForum = true + } + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum), case let .Id(messageId) = message.id, messageId.peerId == peer.id { if let preCachedResources = apiMessage.preCachedResources { for (resource, data) in preCachedResources { updatedState.addPreCachedResource(resource, data: data) @@ -2766,6 +2820,11 @@ private func pollChannel(accountPeerId: PeerId, postbox: Postbox, network: Netwo var resetForumTopics = Set() + var peerIsForum = peer.isForum + if updatedState.isPeerForum(peerId: peer.id) { + peerIsForum = true + } + if let (peer, pts, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, unreadReactionsCount, ttlPeriod) = parameters { updatedState.updateChannelState(peer.peerId, pts: pts) updatedState.updateChannelInvalidationPts(peer.peerId, invalidationPts: pts) @@ -2779,7 +2838,7 @@ private func pollChannel(accountPeerId: PeerId, postbox: Postbox, network: Netwo resetForumTopics.insert(peer.peerId) for apiMessage in messages { - if var message = StoreMessage(apiMessage: apiMessage) { + if var message = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum) { var attributes = message.attributes attributes.append(ChannelMessageStateVersionAttribute(pts: pts)) message = message.withUpdatedAttributes(attributes) diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index dfad00a94b..b85d1b79dc 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -120,7 +120,7 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal map { result -> ([Api.Message], [Api.Chat], [Api.User]) in + |> map { result -> (Peer, [Api.Message], [Api.Chat], [Api.User]) in switch result { case let .messages(messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .messagesSlice(_, _, _, _, messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .channelMessages(_, _, _, _, messages, _, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case .messagesNotModified: - return ([], [], []) + return (peer, [], [], []) } } |> `catch` { _ in - return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + return Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>.single((peer, [], [], [])) } - |> mapToSignal { messages, chats, users -> Signal in + |> mapToSignal { topPeer, messages, chats, users -> Signal in return account.postbox.transaction { transaction -> Void in var peers: [Peer] = [] var peerPresences: [PeerId: Api.User] = [:] @@ -1104,7 +1104,7 @@ public final class AccountViewTracker { updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) for message in messages { - guard let storeMessage = StoreMessage(apiMessage: message) else { + guard let storeMessage = StoreMessage(apiMessage: message, peerIsForum: topPeer.isForum) else { continue } guard case let .Id(id) = storeMessage.id else { diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index af0524bbf1..3b406e9fd5 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -142,7 +142,7 @@ func applyUpdateMessage(postbox: Postbox, stateManager: AccountStateManager, mes var attributes: [MessageAttribute] let text: String let forwardInfo: StoreMessageForwardInfo? - if let apiMessage = apiMessage, let updatedMessage = StoreMessage(apiMessage: apiMessage) { + if let apiMessage = apiMessage, let apiMessagePeerId = apiMessage.peerId, let updatedMessage = StoreMessage(apiMessage: apiMessage, peerIsForum: transaction.getPeer(apiMessagePeerId)?.isForum ?? false) { media = updatedMessage.media attributes = updatedMessage.attributes text = updatedMessage.text @@ -317,7 +317,14 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage var resultMessages: [MessageId: StoreMessage] = [:] for apiMessage in result.messages { - if let resultMessage = StoreMessage(apiMessage: apiMessage, namespace: namespace), case let .Id(id) = resultMessage.id { + var peerIsForum = false + if let apiMessagePeerId = apiMessage.peerId, let peer = transaction.getPeer(apiMessagePeerId) { + if peer.isForum { + peerIsForum = true + } + } + + if let resultMessage = StoreMessage(apiMessage: apiMessage, peerIsForum: peerIsForum, namespace: namespace), case let .Id(id) = resultMessage.id { resultMessages[id] = resultMessage } } diff --git a/submodules/TelegramCore/Sources/State/FetchChatList.swift b/submodules/TelegramCore/Sources/State/FetchChatList.swift index e6dc6c7981..4379ac3b1f 100644 --- a/submodules/TelegramCore/Sources/State/FetchChatList.swift +++ b/submodules/TelegramCore/Sources/State/FetchChatList.swift @@ -153,7 +153,11 @@ private func parseDialogs(apiDialogs: [Api.Dialog], apiMessages: [Api.Message], var lowerNonPinnedIndex: MessageIndex? for message in apiMessages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId, let peer = peers[peerId], peer.isForum { + peerIsForum = true + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { var updatedStoreMessage = storeMessage if case let .Id(id) = storeMessage.id { if let channelPts = channelStates[id.peerId] { diff --git a/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift b/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift index 542d118055..cc389c3faa 100644 --- a/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift +++ b/submodules/TelegramCore/Sources/State/HistoryViewStateValidation.swift @@ -485,7 +485,7 @@ private func hashForMessages(_ messages: [StoreMessage], withChannelIds: Bool) - private enum ValidatedMessages { case notModified - case messages([Api.Message], [Api.Chat], [Api.User], Int32?) + case messages(Peer, [Api.Message], [Api.Chat], [Api.User], Int32?) } private func validateChannelMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, tag: MessageTags?, messageIds: [MessageId], historyState: HistoryState) -> Signal { @@ -546,7 +546,7 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac case .messagesNotModified: return .notModified } - return .messages(messages, chats, users, channelPts) + return .messages(peer, messages, chats, users, channelPts) } } else { return .complete() @@ -615,7 +615,7 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network case .messagesNotModified: return .notModified } - return .messages(messages, chats, users, channelPts) + return .messages(peer, messages, chats, users, channelPts) } } else { return .complete() @@ -656,7 +656,7 @@ private func validateScheduledMessagesBatch(postbox: Postbox, network: Network, case .messagesNotModified: return .notModified } - return .messages(messages, chats, users, nil) + return .messages(peer, messages, chats, users, nil) } } else { signal = .complete() @@ -683,11 +683,11 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran return .complete() } switch result { - case let .messages(messages, _, _, channelPts): + case let .messages(topPeer, messages, _, _, channelPts): var storeMessages: [StoreMessage] = [] for message in messages { - if let storeMessage = StoreMessage(apiMessage: message, namespace: messageNamespace) { + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: topPeer.isForum, namespace: messageNamespace) { var attributes = storeMessage.attributes if let channelPts = channelPts { attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) @@ -734,7 +734,7 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran } var ids = Set() for message in apiMessages { - if let parsedMessage = StoreMessage(apiMessage: message, namespace: messageNamespace), case let .Id(id) = parsedMessage.id { + if let parsedMessage = StoreMessage(apiMessage: message, peerIsForum: topPeer.isForum, namespace: messageNamespace), case let .Id(id) = parsedMessage.id { if let tag = tag { if parsedMessage.tags.contains(tag) { ids.insert(id) @@ -934,11 +934,11 @@ private func validateReplyThreadBatch(postbox: Postbox, network: Network, transa return .complete() } switch result { - case let .messages(messages, _, _, channelPts): + case let .messages(topPeer, messages, _, _, channelPts): var storeMessages: [StoreMessage] = [] for message in messages { - if let storeMessage = StoreMessage(apiMessage: message, namespace: messageNamespace) { + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: topPeer.isForum, namespace: messageNamespace) { var attributes = storeMessage.attributes if let channelPts = channelPts { attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) @@ -983,7 +983,7 @@ private func validateReplyThreadBatch(postbox: Postbox, network: Network, transa } var ids = Set() for message in apiMessages { - if let parsedMessage = StoreMessage(apiMessage: message, namespace: messageNamespace), case let .Id(id) = parsedMessage.id { + if let parsedMessage = StoreMessage(apiMessage: message, peerIsForum: topPeer.isForum, namespace: messageNamespace), case let .Id(id) = parsedMessage.id { ids.insert(id) } } diff --git a/submodules/TelegramCore/Sources/State/Holes.swift b/submodules/TelegramCore/Sources/State/Holes.swift index cfe19705ef..6c5023fed8 100644 --- a/submodules/TelegramCore/Sources/State/Holes.swift +++ b/submodules/TelegramCore/Sources/State/Holes.swift @@ -134,7 +134,7 @@ private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMe } } } else { - var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] + var signals: [Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>] = [] for (peerId, messageIds) in messagesIdsGroupedByPeerId(referencedReplyIds) { if let peer = transaction.getPeer(peerId) ?? peers[peerId] { var signal: Signal? @@ -150,18 +150,18 @@ private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMe |> map { result in switch result { case let .messages(messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .messagesSlice(_, _, _, _, messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users): let _ = apiTopics - return (messages, chats, users) + return (peer, messages, chats, users) case .messagesNotModified: - return ([], [], []) + return (peer, [], [], []) } } |> `catch` { _ in - return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + return Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>.single((peer, [], [], [])) }) } } @@ -181,18 +181,18 @@ private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMe |> map { result in switch result { case let .messages(messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .messagesSlice(_, _, _, _, messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users): let _ = apiTopics - return (messages, chats, users) + return (peer, messages, chats, users) case .messagesNotModified: - return ([], [], []) + return (peer, [], [], []) } } |> `catch` { _ in - return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + return Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>.single((peer, [], [], [])) }) } } @@ -204,10 +204,10 @@ private func withResolvedAssociatedMessages(postbox: Postbox, source: FetchMe |> mapToSignal { results -> Signal in var additionalPeers: [Peer] = [] var additionalMessages: [StoreMessage] = [] - for (messages, chats, users) in results { + for (peer, messages, chats, users) in results { if !messages.isEmpty { for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { additionalMessages.append(message) } } @@ -286,16 +286,19 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH } |> take(1) |> mapToSignal { _ -> Signal in - return postbox.transaction { transaction -> (Api.InputPeer?, Int64) in + return postbox.transaction { transaction -> (Peer?, Int64) in switch peerInput { case let .direct(peerId, _): - return (transaction.getPeer(peerId).flatMap(forceApiInputPeer), 0) + return (transaction.getPeer(peerId), 0) case let .threadFromChannel(channelMessageId): - return (transaction.getPeer(channelMessageId.peerId).flatMap(forceApiInputPeer), 0) + return (transaction.getPeer(channelMessageId.peerId), 0) } } - |> mapToSignal { (inputPeer, hash) -> Signal in - guard let inputPeer = inputPeer else { + |> mapToSignal { (peer, hash) -> Signal in + guard let peer else { + return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet(), actualPeerId: nil, actualThreadId: nil, ids: [])) + } + guard let inputPeer = forceApiInputPeer(peer) else { return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet(), actualPeerId: nil, actualThreadId: nil, ids: [])) } @@ -649,7 +652,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH var storeMessages: [StoreMessage] = [] for message in messages { - if let storeMessage = StoreMessage(apiMessage: message, namespace: namespace) { + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peer.isForum, namespace: namespace) { if let channelPts = channelPts { var attributes = storeMessage.attributes attributes.append(ChannelMessageStateVersionAttribute(pts: channelPts)) @@ -908,8 +911,30 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId var storeMessages: [StoreMessage] = [] var topIndex: MessageIndex? + var peers: [Peer] = [] + var peerPresences: [PeerId: Api.User] = [:] + for chat in chats { + if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { + peers.append(groupOrChannel) + } + } + for user in users { + if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { + peers.append(telegramUser) + peerPresences[telegramUser.id] = user + } + } + var peerMap: [PeerId: Peer] = [:] + for peer in peers { + peerMap[peer.id] = peer + } + for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId, let peer = peerMap[peerId], peer.isForum { + peerIsForum = true + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { storeMessages.append(storeMessage) if let index = storeMessage.index, topIndex == nil || index < topIndex! { topIndex = index @@ -924,20 +949,6 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId transaction.replaceGlobalMessageTagsHole(globalTags: [.Calls, .MissedCalls], index: holeIndex, with: updatedIndex, messages: storeMessages) - var peers: [Peer] = [] - var peerPresences: [PeerId: Api.User] = [:] - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in users { - if let telegramUser = TelegramUser.merge(transaction.getPeer(user.peerId) as? TelegramUser, rhs: user) { - peers.append(telegramUser) - peerPresences[telegramUser.id] = user - } - } - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in return updated }) diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift index 686dde8074..ecb5f89036 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift @@ -151,6 +151,11 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, peers.append(telegramUser) peerPresences[telegramUser.id] = user } + + var peerMap: [PeerId: Peer] = [:] + for peer in peers { + peerMap[peer.id] = peer + } loop: for dialog in dialogs { let apiPeer: Api.Peer @@ -197,7 +202,11 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, } for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId, let peer = peerMap[peerId], peer.isForum { + peerIsForum = true + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { storeMessages.append(storeMessage) } } diff --git a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift index 0bf994384c..b7c342eb97 100644 --- a/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift +++ b/submodules/TelegramCore/Sources/State/UpdatesApiUtils.swift @@ -115,6 +115,19 @@ extension Api.Message { return MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: id) } } + + var peerId: PeerId? { + switch self { + case let .message(_, _, _, messagePeerId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + let peerId: PeerId = messagePeerId.peerId + return peerId + case let .messageEmpty(_, _, peerId): + return peerId?.peerId + case let .messageService(_, _, _, chatPeerId, _, _, _, _): + let peerId: PeerId = chatPeerId.peerId + return peerId + } + } var timestamp: Int32? { switch self { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/FeedHistory.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/FeedHistory.swift index 82933b3cf4..8b13789179 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/FeedHistory.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/FeedHistory.swift @@ -1,538 +1 @@ -import Foundation -import Postbox -import SwiftSignalKit -import TelegramApi -private class FeedHistoryContextImpl { - private let queue: Queue - private let account: Account - private let feedId: Int32 - private let userId: Int64 - - private var currentHole: (MessageHistoryHolesViewEntry, Disposable)? - - struct State: Equatable { - var messageIndices: [MessageIndex] - var holeIndices: [MessageId.Namespace: IndexSet] - } - - let state = Promise() - private var stateValue: State? { - didSet { - if let stateValue = self.stateValue { - if stateValue != oldValue { - self.state.set(.single(stateValue)) - } - } - } - } - - let maxReadOutgoingMessageId = Promise() - private var maxReadOutgoingMessageIdValue: MessageId? { - didSet { - if self.maxReadOutgoingMessageIdValue != oldValue { - self.maxReadOutgoingMessageId.set(.single(self.maxReadOutgoingMessageIdValue)) - } - } - } - - private var maxReadIncomingMessageIdValue: MessageId? - - let unreadCount = Promise() - private var unreadCountValue: Int = 0 { - didSet { - if self.unreadCountValue != oldValue { - self.unreadCount.set(.single(self.unreadCountValue)) - } - } - } - - private var initialStateDisposable: Disposable? - private var holesDisposable: Disposable? - private var readStateDisposable: Disposable? - private var updateInitialStateDisposable: Disposable? - private let readDisposable = MetaDisposable() - - init(queue: Queue, account: Account, feedId: Int32, userId: Int64) { - self.queue = queue - self.account = account - self.feedId = feedId - self.userId = userId - - self.maxReadOutgoingMessageIdValue = nil - self.maxReadOutgoingMessageId.set(.single(self.maxReadOutgoingMessageIdValue)) - - self.maxReadIncomingMessageIdValue = nil - - self.unreadCountValue = 0 - self.unreadCount.set(.single(self.unreadCountValue)) - - self.initialStateDisposable = (account.postbox.transaction { transaction -> State in - return State(messageIndices: [], holeIndices: [Namespaces.Message.Cloud: IndexSet(integersIn: 2 ... 2)]) - } - |> deliverOn(self.queue)).start(next: { [weak self] state in - guard let strongSelf = self else { - return - } - strongSelf.stateValue = state - strongSelf.state.set(.single(state)) - }) - - /*self.updateInitialStateDisposable = (account.network.request(Api.functions.feed.getFeed(flags: 0, filterId: self.feedId, offsetPosition: nil, addOffset: 0, limit: 100, maxPosition: nil, minPosition: nil, hash: 0)) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal<[MessageIndex], NoError> in - return account.postbox.transaction { transaction -> [MessageIndex] in - guard let result = result else { - return [] - } - - let messages: [Api.Message] - let chats: [Api.Chat] - let users: [Api.User] - - switch result { - case let .feedMessages(_, _, _, _, apiMessages, apiChats, apiUsers): - messages = apiMessages - chats = apiChats - users = apiUsers - case .feedMessagesNotModified: - messages = [] - users = [] - chats = [] - } - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in users { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - var storeMessages: [StoreMessage] = [] - - for message in messages { - if let storeMessage = StoreMessage(apiMessage: message, namespace: Namespaces.Message.Cloud) { - storeMessages.append(storeMessage) - } - } - - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) - - let _ = transaction.addMessages(storeMessages, location: .Random) - - return storeMessages.compactMap({ message in - return message.index - }).sorted() - } - } - |> deliverOn(self.queue)).start(next: { [weak self] indices in - guard let strongSelf = self else { - return - } - assert(indices.sorted() == indices) - strongSelf.stateValue = State(messageIndices: indices, holeIndices: [:]) - })*/ - - let userId = self.userId - self.holesDisposable = (account.postbox.messageHistoryHolesView() - |> map { view -> MessageHistoryHolesViewEntry? in - for entry in view.entries { - if entry.userId == userId { - return entry - } - } - return nil - } - |> distinctUntilChanged - |> deliverOn(self.queue)).start(next: { [weak self] entry in - guard let strongSelf = self else { - return - } - strongSelf.setCurrentHole(entry: entry) - }) - - /*self.readStateDisposable = (account.stateManager.threadReadStateUpdates - |> deliverOn(self.queue)).start(next: { [weak self] (_, outgoing) in - guard let strongSelf = self else { - return - } - if let value = outgoing[data.messageId] { - strongSelf.maxReadOutgoingMessageIdValue = MessageId(peerId: data.messageId.peerId, namespace: Namespaces.Message.Cloud, id: value) - } - }) - - let updateInitialState: Signal = account.postbox.transaction { transaction -> Api.InputPeer? in - return transaction.getPeer(data.messageId.peerId).flatMap(apiInputPeer) - } - |> castError(FetchChannelReplyThreadMessageError.self) - |> mapToSignal { inputPeer -> Signal in - guard let inputPeer = inputPeer else { - return .fail(.generic) - } - - return account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: data.messageId.id)) - |> mapError { _ -> FetchChannelReplyThreadMessageError in - return .generic - } - |> mapToSignal { discussionMessage -> Signal in - return account.postbox.transaction { transaction -> Signal in - switch discussionMessage { - case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users): - let parsedMessages = messages.compactMap { message -> StoreMessage? in - StoreMessage(apiMessage: message) - } - - guard let topMessage = parsedMessages.last, let parsedIndex = topMessage.index else { - return .fail(.generic) - } - - var channelMessageId: MessageId? - var replyThreadAttribute: ReplyThreadMessageAttribute? - for attribute in topMessage.attributes { - if let attribute = attribute as? SourceReferenceMessageAttribute { - channelMessageId = attribute.messageId - } else if let attribute = attribute as? ReplyThreadMessageAttribute { - replyThreadAttribute = attribute - } - } - - var peers: [Peer] = [] - var peerPresences: [PeerId: PeerPresence] = [:] - - for chat in chats { - if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { - peers.append(groupOrChannel) - } - } - for user in users { - let telegramUser = TelegramUser(user: user) - peers.append(telegramUser) - if let presence = TelegramUserPresence(apiUser: user) { - peerPresences[telegramUser.id] = presence - } - } - - let _ = transaction.addMessages(parsedMessages, location: .Random) - - updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in - return updated - }) - - updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) - - let resolvedMaxMessage: MessageId? - if let maxId = maxId { - resolvedMaxMessage = MessageId( - peerId: parsedIndex.id.peerId, - namespace: Namespaces.Message.Cloud, - id: maxId - ) - } else { - resolvedMaxMessage = nil - } - - var isChannelPost = false - for attribute in topMessage.attributes { - if let _ = attribute as? SourceReferenceMessageAttribute { - isChannelPost = true - break - } - } - - let maxReadIncomingMessageId = readInboxMaxId.flatMap { readMaxId in - MessageId(peerId: parsedIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: readMaxId) - } - - if let channelMessageId = channelMessageId, let replyThreadAttribute = replyThreadAttribute { - account.viewTracker.updateReplyInfoForMessageId(channelMessageId, info: AccountViewTracker.UpdatedMessageReplyInfo( - timestamp: Int32(CFAbsoluteTimeGetCurrent()), - commentsPeerId: parsedIndex.id.peerId, - maxReadIncomingMessageId: maxReadIncomingMessageId, - maxMessageId: resolvedMaxMessage - )) - - transaction.updateMessage(channelMessageId, update: { currentMessage in - var attributes = currentMessage.attributes - loop: for j in 0 ..< attributes.count { - if let attribute = attributes[j] as? ReplyThreadMessageAttribute { - attributes[j] = ReplyThreadMessageAttribute( - count: replyThreadAttribute.count, - latestUsers: attribute.latestUsers, - commentsPeerId: attribute.commentsPeerId, - maxMessageId: replyThreadAttribute.maxMessageId, - maxReadMessageId: replyThreadAttribute.maxReadMessageId - ) - } - } - return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) - }) - } - - return .single(DiscussionMessage( - messageId: parsedIndex.id, - channelMessageId: channelMessageId, - isChannelPost: isChannelPost, - maxMessage: resolvedMaxMessage, - maxReadIncomingMessageId: maxReadIncomingMessageId, - maxReadOutgoingMessageId: readOutboxMaxId.flatMap { readMaxId in - MessageId(peerId: parsedIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: readMaxId) - }, - unreadCount: Int(unreadCount) - )) - } - } - |> castError(FetchChannelReplyThreadMessageError.self) - |> switchToLatest - } - } - - self.updateInitialStateDisposable = (updateInitialState - |> deliverOnMainQueue).start(next: { [weak self] updatedData in - guard let strongSelf = self else { - return - } - if let maxReadOutgoingMessageId = updatedData.maxReadOutgoingMessageId { - if let current = strongSelf.maxReadOutgoingMessageIdValue { - if maxReadOutgoingMessageId > current { - strongSelf.maxReadOutgoingMessageIdValue = maxReadOutgoingMessageId - } - } else { - strongSelf.maxReadOutgoingMessageIdValue = maxReadOutgoingMessageId - } - } - })*/ - } - - deinit { - self.initialStateDisposable?.dispose() - self.holesDisposable?.dispose() - self.readDisposable.dispose() - self.updateInitialStateDisposable?.dispose() - } - - func setCurrentHole(entry: MessageHistoryHolesViewEntry?) { - if self.currentHole?.0 != entry { - self.currentHole?.1.dispose() - if let entry = entry { - self.currentHole = (entry, self.fetchHole(entry: entry).start(next: { [weak self] updatedState in - guard let strongSelf = self else { - return - } - strongSelf.currentHole = nil - strongSelf.stateValue = updatedState - })) - } else { - self.currentHole = nil - } - } - } - - private func fetchHole(entry: MessageHistoryHolesViewEntry) -> Signal { - //feed.getFeed flags:# filter_id:int offset_to_max_read:flags.3?true offset_position:flags.0?FeedPosition add_offset:int limit:int max_position:flags.1?FeedPosition min_position:flags.2?FeedPosition hash:long = messages.FeedMessages; - return .complete() -// let offsetPosition: Api.FeedPosition? -// let addOffset: Int32 = 0 -// -// switch entry.direction { -// case let .range(start, end): -// if min(start.id, end.id) == 1 && max(start.id, end.id) == Int32.max - 1 { -// offsetPosition = nil -// } else { -// return .never() -// } -// case let .aroundId(id): -// let _ = id -// return .never() -// } -// -// var flags: Int32 = 0 -// if let _ = offsetPosition { -// flags |= 1 << 0 -// } -// -// let account = self.account -// let state = self.stateValue -// return self.account.network.request(Api.functions.feed.getFeed( -// flags: flags, -// filterId: self.feedId, -// offsetPosition: offsetPosition, -// addOffset: addOffset, -// limit: 100, -// maxPosition: nil, -// minPosition: nil, -// hash: 0 -// )) -// |> map(Optional.init) -// |> `catch` { _ -> Signal in -// return .single(nil) -// } -// |> mapToSignal { result -> Signal in -// return account.postbox.transaction { transaction -> State in -// guard let result = result else { -// var updatedState = state ?? State(messageIndices: [], holeIndices: [:]) -// updatedState.holeIndices = [:] -// return updatedState -// } -// -// let messages: [Api.Message] -// let chats: [Api.Chat] -// let users: [Api.User] -// -// switch result { -// case let .feedMessages(_, _, _, _, apiMessages, apiChats, apiUsers): -// messages = apiMessages -// chats = apiChats -// users = apiUsers -// case .feedMessagesNotModified: -// messages = [] -// users = [] -// chats = [] -// } -// -// var peers: [Peer] = [] -// var peerPresences: [PeerId: PeerPresence] = [:] -// for chat in chats { -// if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) { -// peers.append(groupOrChannel) -// } -// } -// for user in users { -// let telegramUser = TelegramUser(user: user) -// peers.append(telegramUser) -// if let presence = TelegramUserPresence(apiUser: user) { -// peerPresences[telegramUser.id] = presence -// } -// } -// -// var storeMessages: [StoreMessage] = [] -// -// for message in messages { -// if let storeMessage = StoreMessage(apiMessage: message, namespace: Namespaces.Message.Cloud) { -// storeMessages.append(storeMessage) -// } -// } -// -// updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in -// return updated -// }) -// updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) -// -// let _ = transaction.addMessages(storeMessages, location: .Random) -// -// var updatedState = state ?? State(messageIndices: [], holeIndices: [:]) -// var currentSet = Set(updatedState.messageIndices) -// -// for index in storeMessages.compactMap(\.index) { -// if !currentSet.contains(index) { -// currentSet.insert(index) -// } -// updatedState.messageIndices.append(index) -// } -// -// updatedState.messageIndices.sort() -// -// updatedState.holeIndices = [:] -// return updatedState -// } -// } - } - - func applyMaxReadIndex(messageIndex: MessageIndex) { - } -} - -public class FeedHistoryContext { - fileprivate final class GuardReference { - private let deallocated: () -> Void - - init(deallocated: @escaping () -> Void) { - self.deallocated = deallocated - } - - deinit { - self.deallocated() - } - } - - private let queue = Queue() - private let impl: QueueLocalObject - - private let userId: Int64 = Int64.random(in: 0 ..< Int64.max) - - public var state: Signal { - let userId = self.userId - - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - let stateDisposable = impl.state.get().start(next: { state in - subscriber.putNext(MessageHistoryViewExternalInput( - content: .messages(indices: state.messageIndices, holes: state.holeIndices, userId: userId), - maxReadIncomingMessageId: nil, - maxReadOutgoingMessageId: nil - )) - }) - disposable.set(stateDisposable) - } - - return disposable - } - } - - public var maxReadOutgoingMessageId: Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - disposable.set(impl.maxReadOutgoingMessageId.get().start(next: { value in - subscriber.putNext(value) - })) - } - - return disposable - } - } - - public var unreadCount: Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - disposable.set(impl.unreadCount.get().start(next: { value in - subscriber.putNext(value) - })) - } - - return disposable - } - } - - public init(account: Account, feedId: Int32) { - let queue = self.queue - let userId = self.userId - self.impl = QueueLocalObject(queue: queue, generate: { - return FeedHistoryContextImpl(queue: queue, account: account, feedId: feedId, userId: userId) - }) - } - - public func applyMaxReadIndex(messageIndex: MessageIndex) { - self.impl.with { impl in - impl.applyMaxReadIndex(messageIndex: messageIndex) - } - } -} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/LoadMessagesIfNecessary.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/LoadMessagesIfNecessary.swift index 2fd9a13a37..6e9a57f288 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/LoadMessagesIfNecessary.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/LoadMessagesIfNecessary.swift @@ -47,8 +47,7 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po if case .cloud = strategy { return postboxSignal |> mapToSignal { (existMessages, missingMessageIds, supportPeers) in - - var signals: [Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>] = [] + var signals: [Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>] = [] for (peerId, messageIds) in messagesIdsGroupedByPeerId(missingMessageIds) { if let peer = supportPeers[peerId] { var signal: Signal? @@ -63,17 +62,17 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po signals.append(signal |> map { result in switch result { case let .messages(messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .messagesSlice(_, _, _, _, messages, chats, users): - return (messages, chats, users) + return (peer, messages, chats, users) case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users): let _ = apiTopics - return (messages, chats, users) + return (peer, messages, chats, users) case .messagesNotModified: - return ([], [], []) + return (peer, [], [], []) } } |> `catch` { _ in - return Signal<([Api.Message], [Api.Chat], [Api.User]), NoError>.single(([], [], [])) + return Signal<(Peer, [Api.Message], [Api.Chat], [Api.User]), NoError>.single((peer, [], [], [])) }) } } @@ -81,13 +80,12 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po return combineLatest(signals) |> mapToSignal { results -> Signal<[Message], NoError> in return postbox.transaction { transaction -> [Message] in - - for (messages, chats, users) in results { + for (peer, messages, chats, users) in results { if !messages.isEmpty { var storeMessages: [StoreMessage] = [] for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { storeMessages.append(message) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReplyThreadHistory.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReplyThreadHistory.swift index 9f2f6c9cd8..b9616dfe28 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReplyThreadHistory.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ReplyThreadHistory.swift @@ -138,12 +138,15 @@ private class ReplyThreadHistoryContextImpl { } }) - let updateInitialState: Signal = account.postbox.transaction { transaction -> Api.InputPeer? in - return transaction.getPeer(data.messageId.peerId).flatMap(apiInputPeer) + let updateInitialState: Signal = account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(data.messageId.peerId) } |> castError(FetchChannelReplyThreadMessageError.self) - |> mapToSignal { inputPeer -> Signal in - guard let inputPeer = inputPeer else { + |> mapToSignal { peer -> Signal in + guard let peer else { + return .fail(.generic) + } + guard let inputPeer = apiInputPeer(peer) else { return .fail(.generic) } @@ -156,7 +159,7 @@ private class ReplyThreadHistoryContextImpl { switch discussionMessage { case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users): let parsedMessages = messages.compactMap { message -> StoreMessage? in - StoreMessage(apiMessage: message) + StoreMessage(apiMessage: message, peerIsForum: peer.isForum) } guard let topMessage = parsedMessages.last, let parsedIndex = topMessage.index else { @@ -605,12 +608,15 @@ public enum FetchChannelReplyThreadMessageError { } func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: MessageId, atMessageId: MessageId?) -> Signal { - return account.postbox.transaction { transaction -> Api.InputPeer? in - return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) + return account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(messageId.peerId) } |> castError(FetchChannelReplyThreadMessageError.self) - |> mapToSignal { inputPeer -> Signal in - guard let inputPeer = inputPeer else { + |> mapToSignal { peer -> Signal in + guard let peer else { + return .fail(.generic) + } + guard let inputPeer = apiInputPeer(peer) else { return .fail(.generic) } @@ -632,7 +638,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa switch discussionMessage { case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, unreadCount, chats, users): let parsedMessages = messages.compactMap { message -> StoreMessage? in - StoreMessage(apiMessage: message) + StoreMessage(apiMessage: message, peerIsForum: peer.isForum) } guard let topMessage = parsedMessages.last, let parsedIndex = topMessage.index else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift index 4dc32065c6..d994b3c075 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SearchMessages.swift @@ -121,7 +121,11 @@ private func mergedState(transaction: Transaction, seedConfiguration: SeedConfig var renderedMessages: [Message] = [] for message in messages { - if let message = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId, let peer = peers[peerId], peer.isForum { + peerIsForum = true + } + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { var associatedThreadInfo: Message.AssociatedThreadInfo? if let threadId = message.threadId, let threadInfo = transaction.getMessageHistoryThreadInfo(peerId: message.id.peerId, threadId: threadId) { associatedThreadInfo = seedConfiguration.decodeMessageThreadInfo(threadInfo.data) @@ -521,7 +525,7 @@ func _internal_downloadMessage(postbox: Postbox, network: Network, messageId: Me var renderedMessages: [Message] = [] for message in messages { - if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { renderedMessages.append(renderedMessage) } } @@ -610,7 +614,11 @@ func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource, var renderedMessages: [Message] = [] for message in messages { - if let message = StoreMessage(apiMessage: message, namespace: id.namespace), case let .Id(updatedId) = message.id { + var peerIsForum = false + if let peerId = message.peerId, let peer = transaction.getPeer(peerId), peer.isForum { + peerIsForum = true + } + if let message = StoreMessage(apiMessage: message, peerIsForum: peerIsForum, namespace: id.namespace), case let .Id(updatedId) = message.id { var addedExisting = false if transaction.getMessage(updatedId) != nil { transaction.updateMessage(updatedId, update: { _ in @@ -655,7 +663,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre messages = [] } for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { return message.index } } @@ -685,7 +693,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre messages = [] } for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: secondaryPeer.isForum) { return message.index } } @@ -709,7 +717,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre messages = [] } for message in messages { - if let message = StoreMessage(apiMessage: message) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { return message.index } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift index 5a37f3d620..369a6abc98 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift @@ -712,111 +712,6 @@ public final class SparseMessageList { } } -/*public final class SparseMessageScrollingContext { - public struct State: Equatable { - public var totalCount: Int - public var minTimestamp: Int32 - } - - private final class Impl { - private let queue: Queue - private let account: Account - private let peerId: PeerId - - let statePromise = Promise() - - private let disposable = MetaDisposable() - - init(queue: Queue, account: Account, peerId: PeerId) { - self.queue = queue - self.account = account - self.peerId = peerId - - self.reload() - } - - deinit { - self.disposable.dispose() - } - - private func reload() { - let account = self.account - let peerId = self.peerId - - let signal: Signal = self.account.postbox.transaction { transaction -> Api.InputPeer? in - return transaction.getPeer(peerId).flatMap(apiInputPeer) - } - |> mapToSignal { inputPeer -> Signal in - guard let inputPeer = inputPeer else { - return .single(nil) - } - return account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 1, offsetDate: 0, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0)) - |> map { result -> State? in - let messages: [Api.Message] - let totalCount: Int - - switch result { - case let .messages(apiMessages, _, _): - messages = apiMessages - totalCount = messages.count - case let .messagesSlice(_, count, _, _, apiMessages, _, _): - messages = apiMessages - totalCount = Int(count) - case let .channelMessages(_, _, count, _, apiMessages, _, _, _): - messages = apiMessages - totalCount = Int(count) - case .messagesNotModified: - messages = [] - totalCount = 0 - } - - if let apiMessage = messages.first, let message = StoreMessage(apiMessage: apiMessage) { - return State(totalCount: totalCount, minTimestamp: message.timestamp) - } else { - return State(totalCount: 0, minTimestamp: 0) - } - } - |> `catch` { _ -> Signal in - return .single(nil) - } - } - - self.disposable.set((signal |> deliverOn(self.queue)).start(next: { [weak self] state in - guard let strongSelf = self else { - return - } - if let state = state { - strongSelf.statePromise.set(.single(state)) - } - })) - } - } - - private let queue: Queue - private let impl: QueueLocalObject - - public var state: Signal { - return Signal { subscriber in - let disposable = MetaDisposable() - - self.impl.with { impl in - disposable.set(impl.statePromise.get().start(next: subscriber.putNext)) - } - - return disposable - } - } - - init(account: Account, peerId: PeerId) { - let queue = Queue() - self.queue = queue - - self.impl = QueueLocalObject(queue: queue, generate: { - return Impl(queue: queue, account: account, peerId: peerId) - }) - } -}*/ - public final class SparseMessageCalendar { private final class Impl { struct InternalState { @@ -908,11 +803,14 @@ public final class SparseMessageCalendar { let account = self.account let peerId = self.peerId let messageTag = self.messageTag - self.disposable.set((self.account.postbox.transaction { transaction -> Api.InputPeer? in - return transaction.getPeer(peerId).flatMap(apiInputPeer) + self.disposable.set((self.account.postbox.transaction { transaction -> Peer? in + return transaction.getPeer(peerId) } - |> mapToSignal { inputPeer -> Signal in - guard let inputPeer = inputPeer else { + |> mapToSignal { peer -> Signal in + guard let peer else { + return .single(LoadResult(messagesByDay: [:], nextOffset: nil, minMessageId: nil, minTimestamp: nil)) + } + guard let inputPeer = apiInputPeer(peer) else { return .single(LoadResult(messagesByDay: [:], nextOffset: nil, minMessageId: nil, minTimestamp: nil)) } guard let messageFilter = messageFilterForTagMask(messageTag) else { @@ -947,7 +845,7 @@ public final class SparseMessageCalendar { } for message in messages { - if let parsedMessage = StoreMessage(apiMessage: message) { + if let parsedMessage = StoreMessage(apiMessage: message, peerIsForum: peer.isForum) { parsedMessages.append(parsedMessage) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index afe99307af..04acd3424e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -491,7 +491,7 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa account.stateManager.addUpdates(updates) var receiptMessageId: MessageId? for apiMessage in updates.messages { - if let message = StoreMessage(apiMessage: apiMessage) { + if let message = StoreMessage(apiMessage: apiMessage, peerIsForum: false) { for media in message.media { if let action = media as? TelegramMediaAction { if case .paymentSent = action.action { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift index ef535ec308..3969bbc49b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChannelAdminEventLogs.swift @@ -195,16 +195,16 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m case .messageEmpty: action = .updatePinned(nil) default: - if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: new, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { action = .updatePinned(rendered) } } case let .channelAdminLogEventActionEditMessage(prev, new): - if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) { + if let prev = StoreMessage(apiMessage: prev, peerIsForum: peer.isForum), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new, peerIsForum: peer.isForum), let newRendered = locallyRenderedMessage(message: new, peers: peers) { action = .editMessage(prev: prevRendered, new: newRendered) } case let .channelAdminLogEventActionDeleteMessage(message): - if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { action = .deleteMessage(rendered) } case .channelAdminLogEventActionParticipantJoin: @@ -238,7 +238,7 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m case let .channelAdminLogEventActionDefaultBannedRights(prevBannedRights, newBannedRights): action = .updateDefaultBannedRights(prev: TelegramChatBannedRights(apiBannedRights: prevBannedRights), new: TelegramChatBannedRights(apiBannedRights: newBannedRights)) case let .channelAdminLogEventActionStopPoll(message): - if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { action = .pollStopped(rendered) } case let .channelAdminLogEventActionChangeLinkedChat(prevValue, newValue): @@ -277,7 +277,7 @@ func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, m case let .channelAdminLogEventActionToggleNoForwards(new): action = .toggleCopyProtection(boolFromApiValue(new)) case let .channelAdminLogEventActionSendMessage(message): - if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), let rendered = locallyRenderedMessage(message: message, peers: peers) { action = .sendMessage(rendered) } case let .channelAdminLogEventActionChangeAvailableReactions(prevValue, newValue): diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift index 0f9804ca34..e4abc7a7a1 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/ChatListFiltering.swift @@ -728,9 +728,18 @@ private func loadAndStorePeerChatInfos(accountPeerId: PeerId, postbox: Postbox, } } + var peerMap: [PeerId: Peer] = [:] + for peer in peers { + peerMap[peer.id] = peer + } + var storeMessages: [StoreMessage] = [] for message in messages { - if let storeMessage = StoreMessage(apiMessage: message) { + var peerIsForum = false + if let peerId = message.peerId, let peer = peerMap[peerId], peer.isForum { + peerIsForum = true + } + if let storeMessage = StoreMessage(apiMessage: message, peerIsForum: peerIsForum) { var updatedStoreMessage = storeMessage if case let .Id(id) = storeMessage.id { if let channelPts = channelStates[id.peerId] { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift index da545effc0..1bf83effde 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/RequestUserPhotos.swift @@ -114,7 +114,7 @@ func _internal_requestPeerPhotos(postbox: Postbox, network: Network, peerId: Pee var renderedMessages: [Message] = [] for message in messages { - if let message = StoreMessage(apiMessage: message), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { + if let message = StoreMessage(apiMessage: message, peerIsForum: peer.isForum), let renderedMessage = locallyRenderedMessage(message: message, peers: peers) { renderedMessages.append(renderedMessage) } } diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 27c48e6034..760a055a88 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -199,6 +199,14 @@ public extension Peer { return false } } + + var isForum: Bool { + if let channel = self as? TelegramChannel { + return channel.flags.contains(.isForum) + } else { + return false + } + } } public extension TelegramPeerUsername { diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index 3c2bd7c1f7..b269161226 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -366,9 +366,8 @@ public final class AccountContextImpl: AccountContext { let context = chatLocationContext(holder: contextHolder, account: self.account, data: data) return .thread(peerId: data.messageId.peerId, threadId: makeMessageThreadId(data.messageId), data: context.state) } - case let .feed(id): - let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id) - return .feed(id: id, data: context.state) + case .feed: + preconditionFailure() } } @@ -391,9 +390,8 @@ public final class AccountContextImpl: AccountContext { let context = chatLocationContext(holder: contextHolder, account: self.account, data: data) return context.maxReadOutgoingMessageId } - case let .feed(id): - let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id) - return context.maxReadOutgoingMessageId + case .feed: + return .single(nil) } } @@ -428,9 +426,8 @@ public final class AccountContextImpl: AccountContext { let context = chatLocationContext(holder: contextHolder, account: self.account, data: data) return context.unreadCount } - case let .feed(id): - let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id) - return context.unreadCount + case .feed: + return .single(0) } } @@ -441,9 +438,8 @@ public final class AccountContextImpl: AccountContext { case let .replyThread(data): let context = chatLocationContext(holder: contextHolder, account: self.account, data: data) context.applyMaxReadIndex(messageIndex: messageIndex) - case let .feed(id): - let context = chatLocationContext(holder: contextHolder, account: self.account, feedId: id) - context.applyMaxReadIndex(messageIndex: messageIndex) + case .feed: + break } } @@ -605,17 +601,6 @@ private func chatLocationContext(holder: Atomic, acc return holder.context } -private func chatLocationContext(holder: Atomic, account: Account, feedId: Int32) -> FeedHistoryContext { - let holder = holder.modify { current in - if let current = current as? ChatLocationFeedContextHolderImpl { - return current - } else { - return ChatLocationFeedContextHolderImpl(account: account, feedId: feedId) - } - } as! ChatLocationFeedContextHolderImpl - return holder.context -} - private final class ChatLocationReplyContextHolderImpl: ChatLocationContextHolder { let context: ReplyThreadHistoryContext @@ -624,14 +609,6 @@ private final class ChatLocationReplyContextHolderImpl: ChatLocationContextHolde } } -private final class ChatLocationFeedContextHolderImpl: ChatLocationContextHolder { - let context: FeedHistoryContext - - init(account: Account, feedId: Int32) { - self.context = FeedHistoryContext(account: account, feedId: feedId) - } -} - func getAppConfiguration(transaction: Transaction) -> AppConfiguration { let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue return appConfiguration