diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 7beeb8e88e..d49783b645 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -473,7 +473,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo filters = [.chats, .media, .links, .files, .music, .voice] } - self.filterContainerNode.update(size: CGSize(width: layout.size.width - 40.0, height: 38.0), sideInset: layout.safeInsets.left - 20.0, filters: filters.map { .filter($0) }, selectedFilter: self.selectedFilterKey, transitionFraction: self.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring)) + let overflowInset: CGFloat = 20.0 + self.filterContainerNode.update(size: CGSize(width: layout.size.width - overflowInset * 2.0, height: 38.0), sideInset: layout.safeInsets.left - overflowInset, filters: filters.map { .filter($0) }, selectedFilter: self.selectedFilterKey, transitionFraction: self.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring)) if let selectedMessageIds = self.stateValue.selectedMessageIds { var wasAdded = false @@ -527,6 +528,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo self.addSubnode(selectionPanelNode) } selectionPanelNode.selectedMessages = selectedMessageIds + let panelHeight = selectionPanelNode.update(layout: layout, presentationData: self.presentationData, transition: wasAdded ? .immediate : transition) let panelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: panelHeight)) if wasAdded { diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index f7f8491536..e3256ea51a 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -571,6 +571,8 @@ public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatLis private struct ChatListSearchListPaneNodeState: Equatable { var expandLocalSearch: Bool = false var expandGlobalSearch: Bool = false + var deletedMessageIds = Set() + var deletedGlobalMessageIds = Set() } private func doesPeerMatchFilter(peer: Peer, filter: ChatListNodePeersFilter) -> Bool { @@ -661,6 +663,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { private let searchContextValue = Atomic(value: nil) var searchCurrentMessages: [Message]? + private var deletedMessagesDisposable: Disposable? + private var searchQueryValue: String? private var searchOptionsValue: ChatListSearchOptions? @@ -1108,6 +1112,11 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { if !foundRemotePeers.2 { index = 0 for message in foundRemoteMessages.0.0 { + if searchState.deletedMessageIds.contains(message.id) { + continue + } else if message.id.namespace == Namespaces.Message.Cloud && searchState.deletedGlobalMessageIds.contains(message.id.id) { + continue + } let headerId = listMessageDateHeaderId(timestamp: message.timestamp) if firstHeaderId == nil { firstHeaderId = headerId @@ -1561,6 +1570,30 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } }) } + + self.deletedMessagesDisposable = (context.account.stateManager.deletedMessages + |> deliverOnMainQueue).start(next: { [weak self] messageIds in + if let strongSelf = self { + strongSelf.updateState { state in + var state = state + var deletedMessageIds = state.deletedMessageIds + var deletedGlobalMessageIds = state.deletedGlobalMessageIds + + for messageId in messageIds { + switch messageId { + case let .messageId(id): + deletedMessageIds.insert(id) + case let .global(id): + deletedGlobalMessageIds.insert(id) + } + } + + state.deletedMessageIds = deletedMessageIds + state.deletedGlobalMessageIds = deletedGlobalMessageIds + return state + } + } + }) } deinit { @@ -1571,6 +1604,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { self.playlistPreloadDisposable?.dispose() self.recentDisposable.dispose() self.updatedRecentPeersDisposable.dispose() + self.deletedMessagesDisposable?.dispose() } override func didLoad() { diff --git a/submodules/ChatListUI/Sources/ChatListSearchMessageSelectionPanelNode.swift b/submodules/ChatListUI/Sources/ChatListSearchMessageSelectionPanelNode.swift index 595f0c060d..366f7027a7 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchMessageSelectionPanelNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchMessageSelectionPanelNode.swift @@ -134,8 +134,8 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode { let width = layout.size.width let insets = layout.insets(options: []) - let leftInset = insets.left - let rightInset = insets.left + let leftInset = insets.left + layout.safeInsets.left + let rightInset = insets.right + layout.safeInsets.right let panelHeight: CGFloat if case .regular = layout.metrics.widthClass, case .regular = layout.metrics.heightClass { diff --git a/submodules/TelegramCore/Sources/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/AccountIntermediateState.swift index 780b8c75c9..79698f31c8 100644 --- a/submodules/TelegramCore/Sources/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/AccountIntermediateState.swift @@ -592,6 +592,7 @@ struct AccountReplayedFinalState { let addedIncomingMessageIds: [MessageId] let wasScheduledMessageIds: [MessageId] let addedSecretMessageIds: [MessageId] + let deletedMessageIds: [DeletedMessageId] let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] let updatedWebpages: [MediaId: TelegramMediaWebpage] let updatedCalls: [Api.PhoneCall] @@ -606,6 +607,7 @@ struct AccountReplayedFinalState { struct AccountFinalStateEvents { let addedIncomingMessageIds: [MessageId] let wasScheduledMessageIds:[MessageId] + let deletedMessageIds: [DeletedMessageId] let updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] let updatedWebpages: [MediaId: TelegramMediaWebpage] let updatedCalls: [Api.PhoneCall] @@ -622,12 +624,13 @@ struct AccountFinalStateEvents { let updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] var isEmpty: Bool { - return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty + return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty } - init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) { + init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:]) { self.addedIncomingMessageIds = addedIncomingMessageIds self.wasScheduledMessageIds = wasScheduledMessageIds + self.deletedMessageIds = deletedMessageIds self.updatedTypingActivities = updatedTypingActivities self.updatedWebpages = updatedWebpages self.updatedCalls = updatedCalls @@ -647,6 +650,7 @@ struct AccountFinalStateEvents { init(state: AccountReplayedFinalState) { self.addedIncomingMessageIds = state.addedIncomingMessageIds self.wasScheduledMessageIds = state.wasScheduledMessageIds + self.deletedMessageIds = state.deletedMessageIds self.updatedTypingActivities = state.updatedTypingActivities self.updatedWebpages = state.updatedWebpages self.updatedCalls = state.updatedCalls @@ -686,6 +690,6 @@ struct AccountFinalStateEvents { let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId) let authorizationListUpdated = self.authorizationListUpdated || other.authorizationListUpdated - return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs })) + return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs })) } } diff --git a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift index 7c589579f0..0086c388b5 100644 --- a/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/AccountStateManagementUtils.swift @@ -2207,6 +2207,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP var delayNotificatonsUntil: Int32? var peerActivityTimestamps: [PeerId: Int32] = [:] var syncChatListFilters = false + var deletedMessageIds: [DeletedMessageId] = [] var holesFromPreviousStateMessageIds: [MessageId] = [] var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:] @@ -2235,7 +2236,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP } } - var wasOpearationScheduledMessegeIds: [MessageId] = [] + var wasOperationScheduledMessageIds: [MessageId] = [] var addedOperationIncomingMessageIds: [MessageId] = [] for operation in finalState.state.operations { @@ -2251,7 +2252,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP } } if message.flags.contains(.WasScheduled) { - wasOpearationScheduledMessegeIds.append(id) + wasOperationScheduledMessageIds.append(id) } } } @@ -2263,9 +2264,9 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP var wasScheduledMessageIds:[MessageId] = [] var addedIncomingMessageIds: [MessageId] = [] - if !wasOpearationScheduledMessegeIds.isEmpty { - let existingIds = transaction.filterStoredMessageIds(Set(wasOpearationScheduledMessegeIds)) - for id in wasOpearationScheduledMessegeIds { + if !wasOperationScheduledMessageIds.isEmpty { + let existingIds = transaction.filterStoredMessageIds(Set(wasOperationScheduledMessageIds)) + for id in wasOperationScheduledMessageIds { if !existingIds.contains(id) { wasScheduledMessageIds.append(id) } @@ -2440,10 +2441,12 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP if !resourceIds.isEmpty { let _ = mediaBox.removeCachedResources(Set(resourceIds)).start() } + deletedMessageIds.append(contentsOf: ids.map { .global($0) }) case let .DeleteMessages(ids): deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids, manualAddMessageThreadStatsDifference: { id, add, remove in addMessageThreadStatsDifference(threadMessageId: id, remove: remove, addedMessagePeer: nil, addedMessageId: nil, isOutgoing: false) }) + deletedMessageIds.append(contentsOf: ids.map { .messageId($0) }) case let .UpdateMinAvailableMessage(id): if let message = transaction.getMessage(id) { updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: id.peerId, minTimestamp: message.timestamp, forceRootGroupIfNotExists: false) @@ -3316,5 +3319,5 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP requestChatListFiltersSync(transaction: transaction) } - return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates) + return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, deletedMessageIds: deletedMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil, updatedIncomingThreadReadStates: updatedIncomingThreadReadStates, updatedOutgoingThreadReadStates: updatedOutgoingThreadReadStates) } diff --git a/submodules/TelegramCore/Sources/AccountStateManager.swift b/submodules/TelegramCore/Sources/AccountStateManager.swift index 9ac18da0a9..a7cf0516cb 100644 --- a/submodules/TelegramCore/Sources/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/AccountStateManager.swift @@ -46,6 +46,11 @@ private final class UpdatedPeersNearbySubscriberContext { let subscribers = Bag<([PeerNearby]) -> Void>() } +public enum DeletedMessageId: Hashable { + case global(Int32) + case messageId(MessageId) +} + public final class AccountStateManager { private let queue = Queue() private let accountPeerId: PeerId @@ -143,6 +148,11 @@ public final class AccountStateManager { return self.threadReadStateUpdatesPipe.signal() } + private let deletedMessagesPipe = ValuePipe<[DeletedMessageId]>() + public var deletedMessages: Signal<[DeletedMessageId], NoError> { + return self.deletedMessagesPipe.signal() + } + private var updatedWebpageContexts: [MediaId: UpdatedWebpageSubscriberContext] = [:] private var updatedPeersNearbyContext = UpdatedPeersNearbySubscriberContext() @@ -740,6 +750,10 @@ public final class AccountStateManager { if events.authorizationListUpdated { self.authorizationListUpdatesPipe.putNext(Void()) } + + if !events.deletedMessageIds.isEmpty { + self.deletedMessagesPipe.putNext(events.deletedMessageIds) + } case let .pollCompletion(pollId, preMessageIds, preSubscribers): if self.operations.count > 1 { self.operations.removeFirst() @@ -1018,6 +1032,10 @@ public final class AccountStateManager { } } + func notifyDeletedMessages(messageIds: [MessageId]) { + self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) }) + } + public func processIncomingCallUpdate(data: Data, completion: @escaping ((CallSessionRingingState, CallSession)?) -> Void) { var rawData = data let reader = BufferReader(Buffer(data: data)) diff --git a/submodules/TelegramCore/Sources/DeleteMessagesInteractively.swift b/submodules/TelegramCore/Sources/DeleteMessagesInteractively.swift index e206ada74b..e5f8730294 100644 --- a/submodules/TelegramCore/Sources/DeleteMessagesInteractively.swift +++ b/submodules/TelegramCore/Sources/DeleteMessagesInteractively.swift @@ -90,6 +90,8 @@ func deleteMessagesInteractively(transaction: Transaction, stateManager: Account } deleteMessages(transaction: transaction, mediaBox: postbox.mediaBox, ids: messageIds) + stateManager?.notifyDeletedMessages(messageIds: messageIds) + if !uniqueIds.isEmpty && removeIfPossiblyDelivered { stateManager?.removePossiblyDeliveredMessages(uniqueIds: uniqueIds) }