From d8e5ff4f5865a444e2d4411e5da41bfe4dabe6c4 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Thu, 28 Dec 2023 19:55:39 +0400 Subject: [PATCH] Various improvements --- .../Sources/AccountContext.swift | 4 +- .../Account/AccountIntermediateState.swift | 7 +- .../Network/FetchedMediaResource.swift | 2 + .../State/AccountStateManagementUtils.swift | 61 +++++++++++++- .../Sources/State/AccountTaskManager.swift | 3 +- ...agedSynchronizePinnedChatsOperations.swift | 81 +++++++++++++++++-- .../SyncCore/SyncCore_Namespaces.swift | 1 + ...Core_SynchronizePinnedChatsOperation.swift | 18 +++++ .../Sources/Utils/MessageUtils.swift | 12 +++ .../Sources/PeerInfoChatListPaneNode.swift | 2 + .../ChatControllerNavigateToMessage.swift | 20 ++++- .../TelegramUI/Sources/ChatController.swift | 8 +- .../Sources/NavigateToChatController.swift | 18 ++--- 13 files changed, 212 insertions(+), 25 deletions(-) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 9b920f112c..909f43f656 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -474,9 +474,10 @@ public final class NavigateToChatControllerParams { public let changeColors: Bool public let setupController: (ChatController) -> Void public let completion: (ChatController) -> Void + public let chatListCompletion: ((ChatListController) -> Void)? public let pushController: ((ChatController, Bool, @escaping () -> Void) -> Void)? - public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, pushController: ((ChatController, Bool, @escaping () -> Void) -> Void)? = nil, completion: @escaping (ChatController) -> Void = { _ in }) { + public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic = Atomic(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, botAppStart: ChatControllerInitialBotAppStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, pushController: ((ChatController, Bool, @escaping () -> Void) -> Void)? = nil, completion: @escaping (ChatController) -> Void = { _ in }, chatListCompletion: @escaping (ChatListController) -> Void = { _ in }) { self.navigationController = navigationController self.chatController = chatController self.chatLocationContextHolder = chatLocationContextHolder @@ -506,6 +507,7 @@ public final class NavigateToChatControllerParams { self.setupController = setupController self.pushController = pushController self.completion = completion + self.chatListCompletion = chatListCompletion } } diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index 310b8b36de..0d1df5f992 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -93,6 +93,7 @@ enum AccountStateMutationOperation { case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32) case AddPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?) case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation) + case UpdatePinnedSavedItemIds(AccountStateUpdatePinnedItemIdsOperation) case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool) case UpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64]) case ReadMessageContents(peerIdsAndMessageIds: (PeerId?, [Int32]), date: Int32?) @@ -571,6 +572,10 @@ struct AccountMutableState { self.addOperation(.UpdatePinnedItemIds(groupId, operation)) } + mutating func addUpdatePinnedSavedItemIds(operation: AccountStateUpdatePinnedItemIdsOperation) { + self.addOperation(.UpdatePinnedSavedItemIds(operation)) + } + mutating func addUpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool) { self.addOperation(.UpdatePinnedTopic(peerId: peerId, threadId: threadId, isPinned: isPinned)) } @@ -665,7 +670,7 @@ struct AccountMutableState { mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization: break case let .AddMessages(messages, location): for message in messages { diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index 1fb83a9ee5..a54d8a540b 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -839,6 +839,8 @@ func revalidateMediaResourceReference(accountPeerId: PeerId, postbox: Postbox, n } if let updatedResource = findUpdatedMediaResource(media: media, previousMedia: nil, resource: resource) { return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } else if let alternativeMedia = item.alternativeMedia, let updatedResource = findUpdatedMediaResource(media: alternativeMedia, previousMedia: nil, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) } else { return .fail(.generic) } diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 0610c48e20..b290d3f72d 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -1490,6 +1490,27 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } else { updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .sync) } + case let .updateSavedDialogPinned(flags, peer): + if case let .dialogPeer(peer) = peer { + if (flags & (1 << 0)) != 0 { + updatedState.addUpdatePinnedSavedItemIds(operation: .pin(.peer(peer.peerId))) + } else { + updatedState.addUpdatePinnedSavedItemIds(operation: .unpin(.peer(peer.peerId))) + } + } + case let .updatePinnedSavedDialogs(_, order): + if let order = order { + updatedState.addUpdatePinnedSavedItemIds(operation: .reorder(order.compactMap { + switch $0 { + case let .dialogPeer(peer): + return .peer(peer.peerId) + case .dialogPeerFolder: + return nil + } + })) + } else { + updatedState.addUpdatePinnedSavedItemIds(operation: .sync) + } case let .updateChannelPinnedTopic(flags, channelId, topicId): let isPinned = (flags & (1 << 0)) != 0 updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: Int64(topicId), isPinned: isPinned) @@ -3231,7 +3252,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddScheduledMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -4228,6 +4249,44 @@ func replayFinalState( case .sync: addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) } + case let .UpdatePinnedSavedItemIds(pinnedOperation): + switch pinnedOperation { + case let .pin(itemId): + switch itemId { + case let .peer(peerId): + var currentItemIds = transaction.getPeerPinnedThreads(peerId: accountPeerId) + if !currentItemIds.contains(peerId.toInt64()) { + currentItemIds.insert(peerId.toInt64(), at: 0) + transaction.setPeerPinnedThreads(peerId: accountPeerId, threadIds: currentItemIds) + } + } + case let .unpin(itemId): + switch itemId { + case let .peer(peerId): + var currentItemIds = transaction.getPeerPinnedThreads(peerId: accountPeerId) + if let index = currentItemIds.firstIndex(of: peerId.toInt64()) { + currentItemIds.remove(at: index) + transaction.setPeerPinnedThreads(peerId: accountPeerId, threadIds: currentItemIds) + } else { + addSynchronizePinnedSavedChatsOperation(transaction: transaction, accountPeerId: accountPeerId) + } + } + case let .reorder(itemIds): + let itemIds = itemIds.compactMap({ + switch $0 { + case let .peer(peerId): + return peerId + } + }) + let currentItemIds = transaction.getPeerPinnedThreads(peerId: accountPeerId) + if Set(itemIds) == Set(currentItemIds.map(PeerId.init)) { + transaction.setPeerPinnedThreads(peerId: accountPeerId, threadIds: itemIds.map { $0.toInt64() }) + } else { + addSynchronizePinnedSavedChatsOperation(transaction: transaction, accountPeerId: accountPeerId) + } + case .sync: + addSynchronizePinnedSavedChatsOperation(transaction: transaction, accountPeerId: accountPeerId) + } case let .UpdatePinnedTopic(peerId, threadId, isPinned): var currentThreadIds = transaction.getPeerPinnedThreads(peerId: peerId) if isPinned { diff --git a/submodules/TelegramCore/Sources/State/AccountTaskManager.swift b/submodules/TelegramCore/Sources/State/AccountTaskManager.swift index 05de1c703b..bbd8f0c454 100644 --- a/submodules/TelegramCore/Sources/State/AccountTaskManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountTaskManager.swift @@ -69,7 +69,8 @@ final class AccountTaskManager { tasks.add(managedSynchronizeGroupMessageStats(network: self.stateManager.network, postbox: self.stateManager.postbox, stateManager: self.stateManager).start()) tasks.add(managedGlobalNotificationSettings(postbox: self.stateManager.postbox, network: self.stateManager.network).start()) - tasks.add(managedSynchronizePinnedChatsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, accountPeerId: self.stateManager.accountPeerId, stateManager: self.stateManager).start()) + tasks.add(managedSynchronizePinnedChatsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, accountPeerId: self.stateManager.accountPeerId, stateManager: self.stateManager, tag: OperationLogTags.SynchronizePinnedChats).start()) + tasks.add(managedSynchronizePinnedChatsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, accountPeerId: self.stateManager.accountPeerId, stateManager: self.stateManager, tag: OperationLogTags.SynchronizePinnedSavedChats).start()) tasks.add(managedSynchronizeGroupedPeersOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager, namespace: .stickers).start()) tasks.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager, namespace: .masks).start()) diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift index 4dea62753c..5db9adc5e3 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizePinnedChatsOperations.swift @@ -4,7 +4,6 @@ import SwiftSignalKit import TelegramApi import MtProtoKit - private final class ManagedSynchronizePinnedChatsOperationsHelper { var operationDisposables: [Int32: Disposable] = [:] @@ -49,10 +48,10 @@ private final class ManagedSynchronizePinnedChatsOperationsHelper { } } -private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { +private func withTakenOperation(postbox: Postbox, tag: PeerOperationLogTag, peerId: PeerId, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { return postbox.transaction { transaction -> Signal in var result: PeerMergedOperationLogEntry? - transaction.operationLogUpdateEntry(peerId: peerId, tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: tagLocalIndex, { entry in + transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in if let entry = entry, let _ = entry.mergedIndex, entry.contents is SynchronizePinnedChatsOperation { result = entry.mergedEntry! return PeerOperationLogEntryUpdate(mergedIndex: .none, contents: .none) @@ -65,11 +64,11 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tagLocalIndex: } |> switchToLatest } -func managedSynchronizePinnedChatsOperations(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager) -> Signal { +func managedSynchronizePinnedChatsOperations(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, tag: PeerOperationLogTag) -> Signal { return Signal { _ in let helper = Atomic(value: ManagedSynchronizePinnedChatsOperationsHelper()) - let disposable = postbox.mergedOperationLogView(tag: OperationLogTags.SynchronizePinnedChats, limit: 10).start(next: { view in + let disposable = postbox.mergedOperationLogView(tag: tag, limit: 10).start(next: { view in let (disposeOperations, beginOperations) = helper.with { helper -> (disposeOperations: [Disposable], beginOperations: [(PeerMergedOperationLogEntry, MetaDisposable)]) in return helper.update(view.entries) } @@ -79,10 +78,14 @@ func managedSynchronizePinnedChatsOperations(postbox: Postbox, network: Network, } for (entry, disposable) in beginOperations { - let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + let signal = withTakenOperation(postbox: postbox, tag: tag, peerId: entry.peerId, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in if let entry = entry { if let operation = entry.contents as? SynchronizePinnedChatsOperation { - return synchronizePinnedChats(transaction: transaction, postbox: postbox, network: network, accountPeerId: accountPeerId, stateManager: stateManager, groupId: PeerGroupId(rawValue: Int32(entry.peerId.id._internalGetInt64Value())), operation: operation) + if tag == OperationLogTags.SynchronizePinnedChats { + return synchronizePinnedChats(transaction: transaction, postbox: postbox, network: network, accountPeerId: accountPeerId, stateManager: stateManager, groupId: PeerGroupId(rawValue: Int32(entry.peerId.id._internalGetInt64Value())), operation: operation) + } else if tag == OperationLogTags.SynchronizePinnedSavedChats { + return synchronizePinnedSavedChats(transaction: transaction, postbox: postbox, network: network, accountPeerId: accountPeerId, stateManager: stateManager, operation: operation) + } } else { assertionFailure() } @@ -90,7 +93,7 @@ func managedSynchronizePinnedChatsOperations(postbox: Postbox, network: Network, return .complete() }) |> then(postbox.transaction { transaction -> Void in - let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: entry.tagLocalIndex) + let _ = transaction.operationLogRemoveEntry(peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex) }) disposable.set((signal |> delay(2.0, queue: Queue.concurrentDefaultQueue())).start()) @@ -279,3 +282,65 @@ private func synchronizePinnedChats(transaction: Transaction, postbox: Postbox, |> switchToLatest } } + +private func synchronizePinnedSavedChats(transaction: Transaction, postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, operation: SynchronizePinnedChatsOperation) -> Signal { + return network.request(Api.functions.messages.getPinnedSavedDialogs()) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { dialogs -> Signal in + guard let dialogs = dialogs else { + return .never() + } + + let _ = dialogs + + /*return postbox.transaction { transaction -> Signal in + var storeMessages: [StoreMessage] = [] + var remoteItemIds: [PeerId] = [] + + let parsedPeers: AccumulatedPeers + + switch dialogs { + case .savedDialogs(let dialogs, let messages, let chats, let users), .savedDialogs(_, let dialogs, let messages, let chats, let users): + parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users) + + loop: for dialog in dialogs { + switch dialog { + case let .savedDialog(_, peer, _): + remoteItemIds.append(peer.peerId) + } + } + + for message in messages { + var peerIsForum = false + if let peerId = message.peerId, let peer = parsedPeers.get(peerId), peer.isForum { + peerIsForum = true + } + if let storeMessage = StoreMessage(apiMessage: message, accountPeerId: accountPeerId, peerIsForum: peerIsForum) { + storeMessages.append(storeMessage) + } + } + case .savedDialogsNotModified: + parsedPeers = AccumulatedPeers(transaction: transaction, chats: [], users: []) + } + + let resultingItemIds: [PeerId] = remoteItemIds + + return postbox.transaction { transaction -> Signal in + updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers) + + transaction.setPeerPinnedThreads(peerId: accountPeerId, threadIds: resultingItemIds.map { $0.toInt64() }) + + let _ = transaction.addMessages(storeMessages, location: .UpperHistoryBlock) + + return .complete() + } + |> switchToLatest + } + |> switchToLatest*/ + + return .complete() + } +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index 6a3dde4997..140799e0b8 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -198,6 +198,7 @@ public struct OperationLogTags { public static let SynchronizeAutosaveItems = PeerOperationLogTag(value: 23) public static let SynchronizeViewStories = PeerOperationLogTag(value: 24) public static let SynchronizePeerStories = PeerOperationLogTag(value: 25) + public static let SynchronizePinnedSavedChats = PeerOperationLogTag(value: 26) } public struct LegacyPeerSummaryCounterTags: OptionSet, Sequence, Hashable { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizePinnedChatsOperation.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizePinnedChatsOperation.swift index 24dd5195fe..d312d46d36 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizePinnedChatsOperation.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_SynchronizePinnedChatsOperation.swift @@ -61,3 +61,21 @@ public func addSynchronizePinnedChatsOperation(transaction: Transaction, groupId } transaction.operationLogAddEntry(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(Int64(rawId))), tag: OperationLogTags.SynchronizePinnedChats, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) } + +public func addSynchronizePinnedSavedChatsOperation(transaction: Transaction, accountPeerId: PeerId) { + var previousItemIds = transaction.getPeerPinnedThreads(peerId: accountPeerId).map { PinnedItemId.peer(PeerId($0)) } + var updateLocalIndex: Int32? + + transaction.operationLogEnumerateEntries(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), tag: OperationLogTags.SynchronizePinnedSavedChats, { entry in + updateLocalIndex = entry.tagLocalIndex + if let contents = entry.contents as? SynchronizePinnedChatsOperation { + previousItemIds = contents.previousItemIds + } + return false + }) + let operationContents = SynchronizePinnedChatsOperation(previousItemIds: previousItemIds) + if let updateLocalIndex = updateLocalIndex { + let _ = transaction.operationLogRemoveEntry(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), tag: OperationLogTags.SynchronizePinnedSavedChats, tagLocalIndex: updateLocalIndex) + } + transaction.operationLogAddEntry(peerId: PeerId(namespace: PeerId.Namespace._internalFromInt32Value(0), id: PeerId.Id._internalFromInt64Value(0)), tag: OperationLogTags.SynchronizePinnedSavedChats, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: operationContents) +} diff --git a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift index 071119fa71..84a3f55f96 100644 --- a/submodules/TelegramCore/Sources/Utils/MessageUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/MessageUtils.swift @@ -296,6 +296,18 @@ func locallyRenderedMessage(message: StoreMessage, peers: AccumulatedPeers, asso public extension Message { func effectivelyIncoming(_ accountPeerId: PeerId) -> Bool { if self.id.peerId == accountPeerId { + if let sourceAuthorInfo = self.sourceAuthorInfo { + if sourceAuthorInfo.originalOutgoing { + return false + } else if let originalAuthor = sourceAuthorInfo.originalAuthor, originalAuthor == accountPeerId { + return false + } + } else if let forwardInfo = self.forwardInfo { + if let author = forwardInfo.author, author.id == accountPeerId { + return false + } + } + if self.forwardInfo != nil { return true } else { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift index 6a96a5d862..97ed3858db 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift @@ -293,6 +293,8 @@ public final class PeerInfoChatListPaneNode: ASDisplayNode, PeerInfoPaneNode, UI } public func scrollToTop() -> Bool { + self.chatListNode.scrollToPosition(.top(adjustForTempInset: false)) + return false } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift index d7037ae911..09c69f5f42 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerNavigateToMessage.swift @@ -10,6 +10,7 @@ import ChatControllerInteraction import OverlayStatusController import TelegramPresentationData import PresentationDataUtils +import UndoUI extension ChatControllerImpl { func navigateToMessage( @@ -149,8 +150,13 @@ extension ChatControllerImpl { } if let navigationController = self.effectiveNavigationController { var chatLocation: NavigateToChatControllerParams.Location = .peer(peer) - if case let .channel(channel) = peer, channel.flags.contains(.isForum), let message = message, let threadId = message.threadId { - chatLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)) + var displayMessageNotFoundToast = false + if case let .channel(channel) = peer, channel.flags.contains(.isForum) { + if let message = message, let threadId = message.threadId { + chatLocation = .replyThread(ChatReplyThreadMessage(peerId: peer.id, threadId: threadId, channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)) + } else { + displayMessageNotFoundToast = true + } } var quote: ChatControllerSubject.MessageHighlight.Quote? @@ -158,7 +164,15 @@ extension ChatControllerImpl { quote = params.quote.flatMap { quote in ChatControllerSubject.MessageHighlight.Quote(string: quote.string, offset: quote.offset) } } - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: chatLocation, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: quote), timecode: nil), keepStack: .always)) + let context = self.context + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: chatLocation, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: quote), timecode: nil), keepStack: .always, chatListCompletion: { chatListController in + if displayMessageNotFoundToast { + let presentationData = context.sharedContext.currentPresentationData.with({ $0 }) + chatListController.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.Conversation_MessageDoesntExist, timeout: nil, customUndoText: nil), elevatedLayout: false, animateInAsReplacement: false, action: { _ in + return true + }), in: .current) + } + })) } completion?() diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 3b5d625dbb..6c1fb5d1f8 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3014,6 +3014,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if case let .replyThread(replyThreadMessage) = strongSelf.chatLocation, replyThreadMessage.effectiveMessageId == message.id { return .none } + if case let .replyThread(replyThreadMessage) = strongSelf.chatLocation, replyThreadMessage.peerId == strongSelf.context.account.peerId { + return .none + } if case .peer = strongSelf.chatLocation, let channel = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum) { if message.threadId == nil { return .none @@ -17472,7 +17475,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if options.contains(.deleteLocally) { var localOptionText = self.presentationData.strings.Conversation_DeleteMessagesForMe - if case .scheduledMessages = self.presentationInterfaceState.subject { + if case .peer(self.context.account.peerId) = self.chatLocation { + //TODO:localize + localOptionText = "Remove from Saved Messages" + } else if case .scheduledMessages = self.presentationInterfaceState.subject { localOptionText = messageIds.count > 1 ? self.presentationData.strings.ScheduledMessages_DeleteMany : self.presentationData.strings.ScheduledMessages_Delete } else { if options.contains(.unsendPersonal) { diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index bf596e3ed2..cddcdac827 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -76,23 +76,23 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam let controller = ChatListControllerImpl(context: params.context, location: .forum(peerId: peer.id), controlsHistoryPreload: false, enableDebugActions: false) let activateMessageSearch = params.activateMessageSearch + let chatListCompletion = params.chatListCompletion params.navigationController.pushViewController(controller, completion: { [weak controller] in - guard let controller, let activateMessageSearch else { + guard let controller else { return } - controller.activateSearch(query: activateMessageSearch.1) + if let activateMessageSearch { + controller.activateSearch(query: activateMessageSearch.1) + } + + if let chatListCompletion { + chatListCompletion(controller) + } }) return } - /*if case let .peer(peer) = params.chatLocation, peer.id == params.context.account.peerId { - let savedMessagesScreen = SavedMessagesScreen(context: params.context) - params.navigationController.pushViewController(savedMessagesScreen, completion: { - }) - return - }*/ - var found = false var isFirst = true if params.useExisting {