From 5a65539234968ee3409cd9a92aaca405c10212f2 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 25 Sep 2020 22:01:11 +0400 Subject: [PATCH 1/3] Fix media validation --- submodules/SyncCore/Sources/TelegramMediaFile.swift | 6 ++++++ .../Sources/ValidationMessageAttribute.swift | 13 +++++++++++++ .../TelegramCore/Sources/AccountManager.swift | 1 + .../TelegramCore/Sources/FetchedMediaResource.swift | 13 ++++++++++++- .../ManagedSecretChatOutgoingOperations.swift | 8 ++++++++ .../Sources/PendingMessageUploadedContent.swift | 2 ++ .../TelegramCore/Sources/TelegramMediaFile.swift | 4 +++- submodules/TelegramUI/Sources/ChatMessageItem.swift | 10 ++++++++++ 8 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 submodules/SyncCore/Sources/ValidationMessageAttribute.swift diff --git a/submodules/SyncCore/Sources/TelegramMediaFile.swift b/submodules/SyncCore/Sources/TelegramMediaFile.swift index 865964df4d..66f8ac0d75 100644 --- a/submodules/SyncCore/Sources/TelegramMediaFile.swift +++ b/submodules/SyncCore/Sources/TelegramMediaFile.swift @@ -9,6 +9,7 @@ private let typeVideo: Int32 = 4 private let typeAudio: Int32 = 5 private let typeHasLinkedStickers: Int32 = 6 private let typeHintFileIsLarge: Int32 = 7 +private let typeHintIsValidated: Int32 = 8 public enum StickerPackReference: PostboxCoding, Hashable, Equatable { case id(id: Int64, accessHash: Int64) @@ -131,6 +132,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding { case Audio(isVoice: Bool, duration: Int, title: String?, performer: String?, waveform: MemoryBuffer?) case HasLinkedStickers case hintFileIsLarge + case hintIsValidated public init(decoder: PostboxDecoder) { let type: Int32 = decoder.decodeInt32ForKey("t", orElse: 0) @@ -156,6 +158,8 @@ public enum TelegramMediaFileAttribute: PostboxCoding { self = .HasLinkedStickers case typeHintFileIsLarge: self = .hintFileIsLarge + case typeHintIsValidated: + self = .hintIsValidated default: preconditionFailure() } @@ -208,6 +212,8 @@ public enum TelegramMediaFileAttribute: PostboxCoding { encoder.encodeInt32(typeHasLinkedStickers, forKey: "t") case .hintFileIsLarge: encoder.encodeInt32(typeHintFileIsLarge, forKey: "t") + case .hintIsValidated: + encoder.encodeInt32(typeHintIsValidated, forKey: "t") } } } diff --git a/submodules/SyncCore/Sources/ValidationMessageAttribute.swift b/submodules/SyncCore/Sources/ValidationMessageAttribute.swift new file mode 100644 index 0000000000..186115c5b0 --- /dev/null +++ b/submodules/SyncCore/Sources/ValidationMessageAttribute.swift @@ -0,0 +1,13 @@ +import Foundation +import Postbox + +public class ValidationMessageAttribute: MessageAttribute { + public init() { + } + + required public init(decoder: PostboxDecoder) { + } + + public func encode(_ encoder: PostboxEncoder) { + } +} diff --git a/submodules/TelegramCore/Sources/AccountManager.swift b/submodules/TelegramCore/Sources/AccountManager.swift index e604d4f956..859e8d3cff 100644 --- a/submodules/TelegramCore/Sources/AccountManager.swift +++ b/submodules/TelegramCore/Sources/AccountManager.swift @@ -167,6 +167,7 @@ private var declaredEncodables: Void = { declareEncodable(Country.self, f: { Country(decoder: $0) }) declareEncodable(Country.CountryCode.self, f: { Country.CountryCode(decoder: $0) }) declareEncodable(CountriesList.self, f: { CountriesList(decoder: $0) }) + declareEncodable(ValidationMessageAttribute.self, f: { ValidationMessageAttribute(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/FetchedMediaResource.swift index f324e6ccdb..33f492620e 100644 --- a/submodules/TelegramCore/Sources/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/FetchedMediaResource.swift @@ -540,7 +540,18 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali if let updatedResource = findUpdatedMediaResource(media: item.file, previousMedia: media, resource: resource) { return postbox.transaction { transaction -> RevalidatedMediaResource in if let id = media.id { - updateMessageMedia(transaction: transaction, id: id, media: item.file) + var attributes = item.file.attributes + if !attributes.contains(where: { attribute in + if case .hintIsValidated = attribute { + return true + } else { + return false + } + }) { + attributes.append(.hintIsValidated) + } + let file = item.file.withUpdatedAttributes(attributes) + updateMessageMedia(transaction: transaction, id: id, media: file) } return RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil) } diff --git a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift index c8015e0f5c..76685ab98e 100644 --- a/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/ManagedSecretChatOutgoingOperations.swift @@ -523,6 +523,8 @@ private func decryptedAttributes46(_ attributes: [TelegramMediaFileAttribute], t break case .hintFileIsLarge: break + case .hintIsValidated: + break } } return result @@ -580,6 +582,10 @@ private func decryptedAttributes73(_ attributes: [TelegramMediaFileAttribute], t break case .hintFileIsLarge: break + case .hintIsValidated: + break + case .hintIsValidated: + break } } return result @@ -637,6 +643,8 @@ private func decryptedAttributes101(_ attributes: [TelegramMediaFileAttribute], break case .hintFileIsLarge: break + case .hintIsValidated: + break } } return result diff --git a/submodules/TelegramCore/Sources/PendingMessageUploadedContent.swift b/submodules/TelegramCore/Sources/PendingMessageUploadedContent.swift index 9feef62447..9370f00b36 100644 --- a/submodules/TelegramCore/Sources/PendingMessageUploadedContent.swift +++ b/submodules/TelegramCore/Sources/PendingMessageUploadedContent.swift @@ -489,6 +489,8 @@ func inputDocumentAttributesFromFileAttributes(_ fileAttributes: [TelegramMediaF attributes.append(.documentAttributeHasStickers) case .hintFileIsLarge: break + case .hintIsValidated: + break case let .Video(duration, size, videoFlags): var flags: Int32 = 0 if videoFlags.contains(.instantRoundVideo) { diff --git a/submodules/TelegramCore/Sources/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/TelegramMediaFile.swift index 8a44e61601..d1285decc8 100644 --- a/submodules/TelegramCore/Sources/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/TelegramMediaFile.swift @@ -155,7 +155,9 @@ func telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: Int32, func telegramMediaFileFromApiDocument(_ document: Api.Document) -> TelegramMediaFile? { switch document { case let .document(_, id, accessHash, fileReference, _, mimeType, size, thumbs, videoThumbs, dcId, attributes): - let parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes) + var parsedAttributes = telegramMediaFileAttributesFromApiAttributes(attributes) + parsedAttributes.append(.hintIsValidated) + let (immediateThumbnail, previewRepresentations) = telegramMediaFileThumbnailRepresentationsFromApiSizes(datacenterId: dcId, documentId: id, accessHash: accessHash, fileReference: fileReference.makeData(), sizes: thumbs ?? []) var videoThumbnails: [TelegramMediaFile.VideoThumbnail] = [] diff --git a/submodules/TelegramUI/Sources/ChatMessageItem.swift b/submodules/TelegramUI/Sources/ChatMessageItem.swift index 7d85a5730f..cda6679a83 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItem.swift @@ -347,10 +347,20 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { if telegramFile.isAnimatedSticker, (self.message.id.peerId.namespace == Namespaces.Peer.SecretChat || !telegramFile.previewRepresentations.isEmpty), let size = telegramFile.size, size > 0 && size <= 128 * 1024 { if self.message.id.peerId.namespace == Namespaces.Peer.SecretChat { if telegramFile.fileId.namespace == Namespaces.Media.CloudFile { + var isValidated = false + for attribute in telegramFile.attributes { + if case .hintIsValidated = attribute { + isValidated = true + break + } + } + inner: for attribute in telegramFile.attributes { if case let .Sticker(_, packReference, _) = attribute { if case .name = packReference { viewClassName = ChatMessageAnimatedStickerItemNode.self + } else if isValidated { + viewClassName = ChatMessageAnimatedStickerItemNode.self } break inner } From 9eea375b667dec2b4b7d0ec935447659b3f70a9f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 26 Sep 2020 00:13:56 +0400 Subject: [PATCH 2/3] Comments [WIP] --- .../Sources/ChatController.swift | 2 +- .../Sources/ChatHistoryLocation.swift | 6 +-- .../Sources/ChatListController.swift | 4 +- .../Sources/ChatListSearchListPaneNode.swift | 2 +- .../Sources/HashtagSearchController.swift | 2 +- .../Sources/ChannelStatsController.swift | 2 +- .../Sources/MessageStatsController.swift | 2 +- .../Sources/TelegramBaseController.swift | 2 +- submodules/TelegramCore/Sources/Holes.swift | 8 ++- .../TelegramCore/Sources/PeerUtils.swift | 3 ++ .../Sources/ReplyThreadHistory.swift | 50 ++++++++++++++----- .../Sources/ApplicationContext.swift | 4 +- .../TelegramUI/Sources/ChatController.swift | 24 ++++----- .../Sources/ChatHistoryListNode.swift | 36 ++++++------- .../Sources/ChatHistoryViewForLocation.swift | 29 ++++++----- .../ChatMessageAnimatedStickerItemNode.swift | 6 ++- .../Sources/ChatMessageBubbleItemNode.swift | 2 +- .../ChatMessageInstantVideoItemNode.swift | 6 ++- .../Sources/ChatMessageStickerItemNode.swift | 6 ++- .../ChatRecentActionsControllerNode.swift | 4 +- .../ChatSearchResultsContollerNode.swift | 2 +- .../Sources/NavigateToChatController.swift | 2 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 2 +- .../OverlayAudioPlayerControllerNode.swift | 4 +- .../PeerInfo/Panes/PeerInfoListPaneNode.swift | 2 +- .../Sources/PeerInfo/PeerInfoScreen.swift | 4 +- .../PreparedChatHistoryViewTransition.swift | 4 +- .../TelegramUI/Sources/TextLinkHandling.swift | 2 +- .../UrlHandling/Sources/UrlHandling.swift | 2 +- 29 files changed, 131 insertions(+), 93 deletions(-) diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 03bd0b2a26..2141b1f10c 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -329,7 +329,7 @@ public struct ChatTextInputStateText: PostboxCoding, Equatable { } public enum ChatControllerSubject: Equatable { - case message(MessageId) + case message(id: MessageId, highlight: Bool) case scheduledMessages } diff --git a/submodules/AccountContext/Sources/ChatHistoryLocation.swift b/submodules/AccountContext/Sources/ChatHistoryLocation.swift index e4e59fd224..7241d181a7 100644 --- a/submodules/AccountContext/Sources/ChatHistoryLocation.swift +++ b/submodules/AccountContext/Sources/ChatHistoryLocation.swift @@ -9,9 +9,9 @@ public enum ChatHistoryInitialSearchLocation: Equatable { public enum ChatHistoryLocation: Equatable { case Initial(count: Int) - case InitialSearch(location: ChatHistoryInitialSearchLocation, count: Int) - case Navigation(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int) - case Scroll(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, sourceIndex: MessageHistoryAnchorIndex, scrollPosition: ListViewScrollPosition, animated: Bool) + case InitialSearch(location: ChatHistoryInitialSearchLocation, count: Int, highlight: Bool) + case Navigation(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, highlight: Bool) + case Scroll(index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, sourceIndex: MessageHistoryAnchorIndex, scrollPosition: ListViewScrollPosition, animated: Bool, highlight: Bool) } public struct ChatHistoryLocationInput: Equatable { diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index e670713562..d92d95676f 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -669,7 +669,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, if let layout = strongSelf.validLayout, case .regular = layout.metrics.widthClass { scrollToEndIfExists = true } - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(messageId), purposefulAction: { + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: .message(id: messageId, highlight: true), purposefulAction: { self?.deactivateSearch(animated: false) }, scrollToEndIfExists: scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [])) strongSelf.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true) @@ -1780,7 +1780,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController, sourceRect = CGRect(x: sourceRect.minX, y: sourceRect.minY + bounds.minY, width: bounds.width, height: bounds.height) sourceRect.size.height -= UIScreenPixel - let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), botStart: nil, mode: .standard(previewing: true)) + let chatController = self.context.sharedContext.makeChatController(context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate) return (chatController, sourceRect) diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index c7618f0e20..b33404b960 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -1726,7 +1726,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } if let id = state.id as? PeerMessagesMediaPlaylistItemId { if type == .music { - let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) + let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60, highlight: true), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) var cancelImpl: (() -> Void)? let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift index e433841dd1..463006184a 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift @@ -57,7 +57,7 @@ public final class HashtagSearchController: TelegramBaseController { if let strongSelf = self { strongSelf.openMessageFromSearchDisposable.set((storedMessageFromSearchPeer(account: strongSelf.context.account, peer: peer) |> deliverOnMainQueue).start(next: { actualPeerId in if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(message.id) : nil, keepStack: .always)) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(actualPeerId), subject: message.id.peerId == actualPeerId ? .message(id: message.id, highlight: true) : nil, keepStack: .always)) } })) strongSelf.controllerNode.listNode.clearHighlightAnimated(true) diff --git a/submodules/StatisticsUI/Sources/ChannelStatsController.swift b/submodules/StatisticsUI/Sources/ChannelStatsController.swift index 1e2a2fb821..b413a660a3 100644 --- a/submodules/StatisticsUI/Sources/ChannelStatsController.swift +++ b/submodules/StatisticsUI/Sources/ChannelStatsController.swift @@ -497,7 +497,7 @@ public func channelStatsController(context: AccountContext, peerId: PeerId, cach } navigateToMessageImpl = { [weak controller] messageId in if let navigationController = controller?.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) } } return controller diff --git a/submodules/StatisticsUI/Sources/MessageStatsController.swift b/submodules/StatisticsUI/Sources/MessageStatsController.swift index 8db5d7f899..fe20ab3a1f 100644 --- a/submodules/StatisticsUI/Sources/MessageStatsController.swift +++ b/submodules/StatisticsUI/Sources/MessageStatsController.swift @@ -258,7 +258,7 @@ public func messageStatsController(context: AccountContext, messageId: MessageId } navigateToMessageImpl = { [weak controller] messageId in if let navigationController = controller?.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always, useExisting: false, purposefulAction: {}, peekData: nil)) } } return controller diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index d248455df0..e97b542b3a 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -557,7 +557,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } if let id = state.id as? PeerMessagesMediaPlaylistItemId { if type == .music { - let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) + let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60, highlight: true), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) var cancelImpl: (() -> Void)? let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramCore/Sources/Holes.swift b/submodules/TelegramCore/Sources/Holes.swift index 5d4e5e1799..852cb4bd93 100644 --- a/submodules/TelegramCore/Sources/Holes.swift +++ b/submodules/TelegramCore/Sources/Holes.swift @@ -155,6 +155,8 @@ enum FetchMessageHistoryHoleThreadInput: CustomStringConvertible { struct FetchMessageHistoryHoleResult: Equatable { var removedIndices: IndexSet var strictRemovedIndices: IndexSet + var actualPeerId: PeerId? + var actualThreadId: Int64? } func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryHoleSource, postbox: Postbox, peerInput: FetchMessageHistoryHoleThreadInput, namespace: MessageId.Namespace, direction: MessageHistoryViewRelativeHoleDirection, space: MessageHistoryHoleSpace, count rawCount: Int) -> Signal { @@ -180,7 +182,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH } |> mapToSignal { (inputPeer, hash) -> Signal in guard let inputPeer = inputPeer else { - return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet())) + return .single(FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet(), actualPeerId: nil, actualThreadId: nil)) } print("fetchMessageHistoryHole for \(peerInput) direction \(direction) space \(space)") @@ -537,7 +539,9 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH return FetchMessageHistoryHoleResult( removedIndices: IndexSet(integersIn: Int(filledRange.lowerBound) ... Int(filledRange.upperBound)), - strictRemovedIndices: strictFilledIndices + strictRemovedIndices: strictFilledIndices, + actualPeerId: storeMessages.first?.id.peerId, + actualThreadId: storeMessages.first?.threadId ) }) } diff --git a/submodules/TelegramCore/Sources/PeerUtils.swift b/submodules/TelegramCore/Sources/PeerUtils.swift index 23f84731d4..6ed76ec717 100644 --- a/submodules/TelegramCore/Sources/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/PeerUtils.swift @@ -227,6 +227,9 @@ public extension RenderedPeer { public func isServicePeer(_ peer: Peer) -> Bool { if let peer = peer as? TelegramUser { + if peer.id.isReplies { + return true + } return (peer.id.namespace == Namespaces.Peer.CloudUser && (peer.id.id == 777000 || peer.id.id == 333000)) } return false diff --git a/submodules/TelegramCore/Sources/ReplyThreadHistory.swift b/submodules/TelegramCore/Sources/ReplyThreadHistory.swift index b94ef635fc..75bab2744f 100644 --- a/submodules/TelegramCore/Sources/ReplyThreadHistory.swift +++ b/submodules/TelegramCore/Sources/ReplyThreadHistory.swift @@ -374,9 +374,9 @@ public class ReplyThreadHistoryContext { } public struct ChatReplyThreadMessage: Equatable { - public enum Anchor { + public enum Anchor: Equatable { case automatic - case lowerBound + case lowerBoundMessage(MessageIndex) } public var messageId: MessageId @@ -606,17 +606,13 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI } let inputAnchor: HistoryViewInputAnchor - let initialAnchor: ChatReplyThreadMessage.Anchor switch anchor { case .lowerBound: inputAnchor = .lowerBound - initialAnchor = .lowerBound case .upperBound: inputAnchor = .upperBound - initialAnchor = .automatic case let .message(id): inputAnchor = .message(id) - initialAnchor = .automatic } let testView = transaction.getMessagesHistoryViewState( @@ -635,27 +631,57 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI namespaces: .not(Namespaces.Message.allScheduled) ) if !testView.isLoading { + let initialAnchor: ChatReplyThreadMessage.Anchor + switch anchor { + case .lowerBound: + if let entry = testView.entries.first { + initialAnchor = .lowerBoundMessage(entry.index) + } else { + initialAnchor = .automatic + } + case .upperBound: + initialAnchor = .automatic + case .message: + initialAnchor = .automatic + } + return .single((FetchMessageHistoryHoleResult(removedIndices: IndexSet(), strictRemovedIndices: IndexSet()), initialAnchor)) } } let direction: MessageHistoryViewRelativeHoleDirection - let initialAnchor: ChatReplyThreadMessage.Anchor switch anchor { case .lowerBound: direction = .range(start: MessageId(peerId: commentsPeerId, namespace: Namespaces.Message.Cloud, id: 1), end: MessageId(peerId: commentsPeerId, namespace: Namespaces.Message.Cloud, id: Int32.max - 1)) - initialAnchor = .lowerBound case .upperBound: direction = .range(start: MessageId(peerId: commentsPeerId, namespace: Namespaces.Message.Cloud, id: Int32.max - 1), end: MessageId(peerId: commentsPeerId, namespace: Namespaces.Message.Cloud, id: 1)) - initialAnchor = .automatic case let .message(id): direction = .aroundId(id) - initialAnchor = .automatic } return fetchMessageHistoryHole(accountPeerId: account.peerId, source: .network(account.network), postbox: account.postbox, peerInput: peerInput, namespace: Namespaces.Message.Cloud, direction: direction, space: .everywhere, count: 40) |> castError(FetchChannelReplyThreadMessageError.self) - |> map { result -> (FetchMessageHistoryHoleResult, ChatReplyThreadMessage.Anchor) in - return (result, initialAnchor) + |> mapToSignal { result -> Signal<(FetchMessageHistoryHoleResult, ChatReplyThreadMessage.Anchor), FetchChannelReplyThreadMessageError> in + return account.postbox.transaction { transaction -> (FetchMessageHistoryHoleResult, ChatReplyThreadMessage.Anchor) in + let initialAnchor: ChatReplyThreadMessage.Anchor + switch anchor { + case .lowerBound: + if let actualPeerId = result.actualPeerId, let actualThreadId = result.actualThreadId { + if let firstMessage = transaction.getMessagesWithThreadId(peerId: actualPeerId, namespace: Namespaces.Message.Cloud, threadId: actualThreadId, from: MessageIndex.lowerBound(peerId: actualPeerId, namespace: Namespaces.Message.Cloud), includeFrom: false, to: MessageIndex.upperBound(peerId: actualPeerId, namespace: Namespaces.Message.Cloud), limit: 1).first { + initialAnchor = .lowerBoundMessage(firstMessage.index) + } else { + initialAnchor = .automatic + } + } else { + initialAnchor = .automatic + } + case .upperBound: + initialAnchor = .automatic + case .message: + initialAnchor = .automatic + } + return (result, initialAnchor) + } + |> castError(FetchChannelReplyThreadMessageError.self) } } |> castError(FetchChannelReplyThreadMessageError.self) diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index 0c08fc926f..ceab4ab7b8 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -702,7 +702,7 @@ final class AuthorizedApplicationContext { } let navigateToMessage = { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(messageId))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: strongSelf.rootController, context: strongSelf.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true))) } if chatIsVisible { @@ -773,7 +773,7 @@ final class AuthorizedApplicationContext { if visiblePeerId != peerId || messageId != nil { if self.rootController.rootTabController != nil { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message($0) }, activateInput: activateInput)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: .peer(peerId), subject: messageId.flatMap { .message(id: $0, highlight: true) }, activateInput: activateInput)) } else { self.scheduledOpenChatWithPeerId = (peerId, messageId, activateInput) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 26274f8558..847a09c0d7 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -5115,7 +5115,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let navigationController = strongSelf.effectiveNavigationController { - let subject: ChatControllerSubject? = sourceMessageId.flatMap(ChatControllerSubject.message) + let subject: ChatControllerSubject? = sourceMessageId.flatMap { ChatControllerSubject.message(id: $0, highlight: true) } strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadResult), subject: subject, keepStack: .always)) } }, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get())) @@ -8189,7 +8189,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func scrollToEndOfHistory() { - let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true), id: 0) + let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true, highlight: false), id: 0) let historyView = preloadedChatHistoryViewForLocation(locationInput, context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView @@ -8253,7 +8253,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } func scrollToStartOfHistory() { - let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: 0) + let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true, highlight: false), id: 0) let historyView = preloadedChatHistoryViewForLocation(locationInput, context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView @@ -8400,9 +8400,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let subject: ChatControllerSubject? if let atMessageId = atMessageId { - subject = .message(atMessageId) - } else if result.scrollToLowerBound { - subject = .message(MessageId(peerId: result.message.messageId.peerId, namespace: Namespaces.Message.Cloud, id: 1)) + subject = .message(id: atMessageId, highlight: true) + } else if let index = result.scrollToLowerBoundMessage { + subject = .message(id: index.id, highlight: false) } else { subject = nil } @@ -8456,7 +8456,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if case let .peer(peerId) = self.chatLocation, let messageId = messageLocation.messageId, (messageId.peerId != peerId && !forceInCurrentChat) || (self.presentationInterfaceState.isScheduledMessages && messageId.id != 0 && !Namespaces.Message.allScheduled.contains(messageId.namespace)) { if let navigationController = self.effectiveNavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(messageId), keepStack: .always)) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageId.peerId), subject: .message(id: messageId, highlight: true), keepStack: .always)) } } else if forceInCurrentChat { if let _ = fromId, let fromIndex = fromIndex, rememberInStack { @@ -8491,7 +8491,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .upperBound: searchLocation = .index(MessageIndex.upperBound(peerId: self.chatLocation.peerId)) } - let historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(location: searchLocation, count: 50), id: 0), context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) + let historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(location: searchLocation, count: 50, highlight: true), id: 0), context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView |> mapToSignal { historyView -> Signal<(MessageIndex?, Bool), NoError> in switch historyView { @@ -8583,7 +8583,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.historyNavigationStack.add(fromIndex) } self.loadingMessage.set(true) - let historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(location: searchLocation, count: 50), id: 0), context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) + let historyView = preloadedChatHistoryViewForLocation(ChatHistoryLocationInput(content: .InitialSearch(location: searchLocation, count: 50, highlight: true), id: 0), context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: []) let signal = historyView |> mapToSignal { historyView -> Signal in switch historyView { @@ -8606,7 +8606,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G completion?() } else { if let navigationController = strongSelf.effectiveNavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message($0) })) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true) })) } completion?() } @@ -8618,7 +8618,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) } else { if let navigationController = self.effectiveNavigationController { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message($0) })) + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message(id: $0, highlight: true) })) } completion?() } @@ -9205,7 +9205,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G switch navigation { case let .chat(_, subject, peekData): if case .peer(peerId) = strongSelf.chatLocation { - if let subject = subject, case let .message(messageId) = subject { + if let subject = subject, case let .message(messageId, _) = subject { strongSelf.navigateToMessage(from: nil, to: .id(messageId)) } } else if let navigationController = strongSelf.effectiveNavigationController { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 60630a7cdc..cb1c6ce36f 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -83,7 +83,7 @@ public enum ChatHistoryListMode: Equatable { enum ChatHistoryViewScrollPosition { case unread(index: MessageIndex) case positionRestoration(index: MessageIndex, relativeOffset: CGFloat) - case index(index: MessageHistoryAnchorIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool) + case index(index: MessageHistoryAnchorIndex, position: ListViewScrollPosition, directionHint: ListViewScrollToItemDirectionHint, animated: Bool, highlight: Bool) } enum ChatHistoryViewUpdateType { @@ -399,9 +399,9 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist private extension ChatHistoryLocationInput { var isAtUpperBound: Bool { switch self.content { - case .Navigation(index: .upperBound, anchorIndex: .upperBound, count: _): + case .Navigation(index: .upperBound, anchorIndex: .upperBound, count: _, highlight: _): return true - case .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: _, scrollPosition: _, animated: _): + case .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: _, scrollPosition: _, animated: _, highlight: _): return true default: return false @@ -795,10 +795,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if let filteredEntries = historyView?.filteredEntries, let visibleRange = displayRange.visibleRange { let lastEntry = filteredEntries[filteredEntries.count - 1 - visibleRange.lastIndex] - strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount, highlight: false), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) } else { - if let subject = subject, case let .message(messageId) = subject { - strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) + if let subject = subject, case let .message(messageId, highlight) = subject { + strongSelf.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: (strongSelf.chatHistoryLocationValue?.id).flatMap({ $0 + 1 }) ?? 0) } else if var chatHistoryLocation = strongSelf.chatHistoryLocationValue { chatHistoryLocation.id += 1 strongSelf.chatHistoryLocationValue = chatHistoryLocation @@ -886,10 +886,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if scrollPosition == nil, let originalScrollPosition = originalScrollPosition { switch originalScrollPosition { - case let .index(index, position, _, _): + case let .index(index, position, _, _, highlight): if case .upperBound = index { if let previous = previous, previous.filteredEntries.isEmpty { - updatedScrollPosition = .index(index: index, position: position, directionHint: .Down, animated: false) + updatedScrollPosition = .index(index: index, position: position, directionHint: .Down, animated: false, highlight: highlight) } } default: @@ -972,8 +972,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } }) - if let subject = subject, case let .message(messageId) = subject { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60), id: 0) + if let subject = subject, case let .message(messageId, highlight) = subject { + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .InitialSearch(location: .id(messageId), count: 60, highlight: highlight), id: 0) } else { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Initial(count: 60), id: 0) } @@ -1334,14 +1334,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { if let loaded = displayedRange.loadedRange, let firstEntry = historyView.filteredEntries.first, let lastEntry = historyView.filteredEntries.last { if loaded.firstIndex < 5 && historyView.originalView.laterId != nil { - let locationInput: ChatHistoryLocation = .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount) + let locationInput: ChatHistoryLocation = .Navigation(index: .message(lastEntry.index), anchorIndex: .message(lastEntry.index), count: historyMessageCount, highlight: false) if self.chatHistoryLocationValue?.content != locationInput { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) } } else if loaded.firstIndex < 5, historyView.originalView.laterId == nil, !historyView.originalView.holeLater, let chatHistoryLocationValue = self.chatHistoryLocationValue, !chatHistoryLocationValue.isAtUpperBound, historyView.originalView.anchorIndex != .upperBound { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .upperBound, anchorIndex: .upperBound, count: historyMessageCount), id: self.takeNextHistoryLocationId()) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Navigation(index: .upperBound, anchorIndex: .upperBound, count: historyMessageCount, highlight: false), id: self.takeNextHistoryLocationId()) } else if loaded.lastIndex >= historyView.filteredEntries.count - 5 && historyView.originalView.earlierId != nil { - let locationInput: ChatHistoryLocation = .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount) + let locationInput: ChatHistoryLocation = .Navigation(index: .message(firstEntry.index), anchorIndex: .message(firstEntry.index), count: historyMessageCount, highlight: false) if self.chatHistoryLocationValue?.content != locationInput { self.chatHistoryLocationValue = ChatHistoryLocationInput(content: locationInput, id: self.takeNextHistoryLocationId()) } @@ -1373,7 +1373,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { currentMessage = messages.first?.0 } if let message = currentMessage, let anchorMessage = self.anchorMessageInCurrentHistoryView() { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(message.index), anchorIndex: .message(message.index), sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: self.takeNextHistoryLocationId()) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(message.index), anchorIndex: .message(message.index), sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true, highlight: false), id: self.takeNextHistoryLocationId()) } } } @@ -1402,13 +1402,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { } if let currentMessage = currentMessage { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(currentMessage.index), anchorIndex: .message(currentMessage.index), sourceIndex: .upperBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId()) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(currentMessage.index), anchorIndex: .message(currentMessage.index), sourceIndex: .upperBound, scrollPosition: .top(0.0), animated: true, highlight: true), id: self.takeNextHistoryLocationId()) } } } public func scrollToStartOfHistory() { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: self.takeNextHistoryLocationId()) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true, highlight: false), id: self.takeNextHistoryLocationId()) } public func scrollToEndOfHistory() { @@ -1416,13 +1416,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { case .known(0.0): break default: - let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true), id: self.takeNextHistoryLocationId()) + let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .upperBound, anchorIndex: .upperBound, sourceIndex: .lowerBound, scrollPosition: .top(0.0), animated: true, highlight: false), id: self.takeNextHistoryLocationId()) self.chatHistoryLocationValue = locationInput } } public func scrollToMessage(from fromIndex: MessageIndex, to toIndex: MessageIndex, animated: Bool, highlight: Bool = true, scrollPosition: ListViewScrollPosition = .center(.bottom)) { - self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(toIndex), anchorIndex: .message(toIndex), sourceIndex: .message(fromIndex), scrollPosition: scrollPosition, animated: animated), id: self.takeNextHistoryLocationId()) + self.chatHistoryLocationValue = ChatHistoryLocationInput(content: .Scroll(index: .message(toIndex), anchorIndex: .message(toIndex), sourceIndex: .message(fromIndex), scrollPosition: scrollPosition, animated: animated, highlight: highlight), id: self.takeNextHistoryLocationId()) } public func anchorMessageInCurrentHistoryView() -> Message? { diff --git a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift index 0f6a3a58ad..abe9135fcd 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryViewForLocation.swift @@ -32,9 +32,9 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A if scheduled { var first = true var chatScrollPosition: ChatHistoryViewScrollPosition? - if case let .Scroll(index, _, sourceIndex, position, animated) = location.content { + if case let .Scroll(index, _, sourceIndex, position, animated, highlight) = location.content { let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up - chatScrollPosition = .index(index: index, position: position, directionHint: directionHint, animated: animated) + chatScrollPosition = .index(index: index, position: position, directionHint: directionHint, animated: animated, highlight: highlight) } return account.viewTracker.scheduledMessagesViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in @@ -146,7 +146,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A return .HistoryView(view: view, type: .Initial(fadeIn: fadeIn), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id) } } - case let .InitialSearch(searchLocation, count): + case let .InitialSearch(searchLocation, count, highlight): var preloaded = false var fadeIn = false @@ -198,10 +198,10 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A } preloaded = true - return .HistoryView(view: view, type: reportUpdateType, scrollPosition: .index(index: anchorIndex, position: .center(.bottom), directionHint: .Down, animated: false), flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id) + return .HistoryView(view: view, type: reportUpdateType, scrollPosition: .index(index: anchorIndex, position: .center(.bottom), directionHint: .Down, animated: false, highlight: highlight), flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id) } } - case let .Navigation(index, anchorIndex, count): + case let .Navigation(index, anchorIndex, count, highlight): var first = true return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: index, anchorIndex: anchorIndex, count: count, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation) @@ -215,9 +215,9 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A } return .HistoryView(view: view, type: .Generic(type: genericType), scrollPosition: nil, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: initialData, buttonKeyboardMessage: view.topTaggedMessages.first, cachedData: cachedData, cachedDataMessages: cachedDataMessages, readStateData: readStateData), id: location.id) } - case let .Scroll(index, anchorIndex, sourceIndex, scrollPosition, animated): + case let .Scroll(index, anchorIndex, sourceIndex, scrollPosition, animated, highlight): let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up - let chatScrollPosition = ChatHistoryViewScrollPosition.index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated) + let chatScrollPosition = ChatHistoryViewScrollPosition.index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated, highlight: highlight) var first = true return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: index, anchorIndex: anchorIndex, count: 128, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in @@ -305,7 +305,7 @@ struct ReplyThreadInfo { var message: ChatReplyThreadMessage var isChannelPost: Bool var isEmpty: Bool - var scrollToLowerBound: Bool + var scrollToLowerBoundMessage: MessageIndex? var contextHolder: Atomic } @@ -326,12 +326,12 @@ func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThrea let chatLocationContextHolder = Atomic(value: nil) let input: ChatHistoryLocationInput - let scrollToLowerBound: Bool + var scrollToLowerBoundMessage: MessageIndex? switch replyThreadMessage.initialAnchor { case .automatic: if let atMessageId = atMessageId { input = ChatHistoryLocationInput( - content: .InitialSearch(location: .id(atMessageId), count: 40), + content: .InitialSearch(location: .id(atMessageId), count: 40, highlight: true), id: 0 ) } else { @@ -340,13 +340,12 @@ func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThrea id: 0 ) } - scrollToLowerBound = false - case .lowerBound: + case let .lowerBoundMessage(index): input = ChatHistoryLocationInput( - content: .Navigation(index: .lowerBound, anchorIndex: .lowerBound, count: 40), + content: .Navigation(index: .message(index), anchorIndex: .message(index), count: 40, highlight: false), id: 0 ) - scrollToLowerBound = true + scrollToLowerBoundMessage = index } let preloadSignal = preloadedChatHistoryViewForLocation( @@ -380,7 +379,7 @@ func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThrea message: replyThreadMessage, isChannelPost: replyThreadMessage.isChannelPost, isEmpty: isEmpty, - scrollToLowerBound: scrollToLowerBound, + scrollToLowerBoundMessage: scrollToLowerBoundMessage, contextHolder: chatLocationContextHolder ) } diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 21c8427ac4..b6701149c9 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1127,7 +1127,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) } } @@ -1259,7 +1259,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } - if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { + if item.content.firstMessage.id.peerId.isReplies { + item.controllerInteraction.openReplyThreadOriginalMessage(item.content.firstMessage) + } else if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { item.controllerInteraction.navigateToMessage(item.content.firstMessage.id, attribute.messageId) diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 373d88b05f..c9b2a4f71e 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -2502,7 +2502,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index a353a141a0..49b7868aa3 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -672,7 +672,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) } } @@ -754,7 +754,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { } } - if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { + if item.content.firstMessage.id.peerId.isReplies { + item.controllerInteraction.openReplyThreadOriginalMessage(item.content.firstMessage) + } else if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { item.controllerInteraction.navigateToMessage(item.content.firstMessage.id, attribute.messageId) diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 6516c1f007..25b0a27f45 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -735,7 +735,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { openPeerId = attribute.messageId.peerId - navigate = .chat(textInputState: nil, subject: .message(attribute.messageId), peekData: nil) + navigate = .chat(textInputState: nil, subject: .message(id: attribute.messageId, highlight: true), peekData: nil) } } @@ -820,7 +820,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } } - if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { + if item.content.firstMessage.id.peerId.isReplies { + item.controllerInteraction.openReplyThreadOriginalMessage(item.content.firstMessage) + } else if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { for attribute in item.content.firstMessage.attributes { if let attribute = attribute as? SourceReferenceMessageAttribute { item.controllerInteraction.navigateToMessage(item.content.firstMessage.id, attribute.messageId) diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 0f1631d1ac..e73b020249 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -815,11 +815,11 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { break case let .channelMessage(peerId, messageId): if let navigationController = strongSelf.getNavigationController() { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(messageId))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true))) } case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = strongSelf.getNavigationController() { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(messageId))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .replyThread(replyThreadMessage), subject: .message(id: messageId, highlight: true))) } case let .stickerPack(name): let packReference: StickerPackReference = .name(name) diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index a69e9c64c8..93a5f73095 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -196,7 +196,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe switch item.content { case let .peer(peer): if let message = peer.messages.first { - let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(message.id), botStart: nil, mode: .standard(previewing: true)) + let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: .message(id: message.id, highlight: true), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single([]), reactionItems: [], gesture: gesture) presentInGlobalOverlay(contextController) diff --git a/submodules/TelegramUI/Sources/NavigateToChatController.swift b/submodules/TelegramUI/Sources/NavigateToChatController.swift index 233d8cd066..22848f2286 100644 --- a/submodules/TelegramUI/Sources/NavigateToChatController.swift +++ b/submodules/TelegramUI/Sources/NavigateToChatController.swift @@ -20,7 +20,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam if let updateTextInputState = params.updateTextInputState { controller.updateTextInputState(updateTextInputState) } - if let subject = params.subject, case let .message(messageId) = subject { + if let subject = params.subject, case let .message(messageId, _) = subject { let navigationController = params.navigationController let animated = params.animated controller.navigateToMessage(messageLocation: .id(messageId), animated: isFirst, completion: { [weak navigationController, weak controller] in diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index 8ddbdc9500..b10f952798 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -89,7 +89,7 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur dismissInput() navigationController?.pushViewController(controller) case let .channelMessage(peerId, messageId): - openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId), peekData: nil)) + openPeer(peerId, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true), peekData: nil)) case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = navigationController { let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 3bc0f9691d..f0d348eaad 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -165,7 +165,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu let chatLocationContextHolder = Atomic(value: nil) - self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(initialMessageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: isGlobalSearch)) + self.historyNode = ChatHistoryListNode(context: context, chatLocation: .peer(peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: initialMessageId, highlight: true), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: isGlobalSearch)) super.init() @@ -496,7 +496,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu } let chatLocationContextHolder = Atomic(value: nil) - let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(messageId), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + let historyNode = ChatHistoryListNode(context: self.context, chatLocation: .peer(self.peerId), chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: messageId, highlight: true), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) historyNode.preloadPages = true historyNode.stackFromBottom = true historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift index de270ceb40..ea63e93b1d 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift @@ -256,7 +256,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { } if let id = state.id as? PeerMessagesMediaPlaylistItemId { if type == .music { - let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) + let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(location: .id(id.messageId), count: 60, highlight: true), id: 0), context: strongSelf.context, chatLocation: .peer(id.messageId.peerId), chatLocationContextHolder: Atomic(value: nil), tagMask: MessageTags.music) var cancelImpl: (() -> Void)? let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index a9e53fa223..6873b25754 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1600,7 +1600,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, _ in c.dismiss(completion: { if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(id: message.id, highlight: true))) } }) }))) @@ -1703,7 +1703,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD items.append(.action(ContextMenuActionItem(text: strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { c, f in c.dismiss(completion: { if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { - strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(message.id))) + strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId), subject: .message(id: message.id, highlight: true))) } }) }))) diff --git a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift index 1efca4fc26..cdc8293c66 100644 --- a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift +++ b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift @@ -143,8 +143,8 @@ func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toVie index += 1 } } - case let .index(scrollIndex, position, directionHint, animated): - if case .center = position { + case let .index(scrollIndex, position, directionHint, animated, highlight): + if case .center = position, highlight { scrolledToIndex = scrollIndex } var index = toView.filteredEntries.count - 1 diff --git a/submodules/TelegramUI/Sources/TextLinkHandling.swift b/submodules/TelegramUI/Sources/TextLinkHandling.swift index fbabf1690d..e981b5c7cd 100644 --- a/submodules/TelegramUI/Sources/TextLinkHandling.swift +++ b/submodules/TelegramUI/Sources/TextLinkHandling.swift @@ -57,7 +57,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate openResolvedPeerImpl(peerId, .default) case let .channelMessage(peerId, messageId): if let navigationController = controller.navigationController as? NavigationController { - context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(messageId))) + context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true))) } case let .replyThreadMessage(replyThreadMessage, messageId): if let navigationController = controller.navigationController as? NavigationController { diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 75a45279eb..42576e6876 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -383,7 +383,7 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig return .replyThreadMessage(replyThreadMessage: result, messageId: messageId) } } else { - return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(messageId), peekData: nil))) + return .single(.peer(foundPeer.id, .chat(textInputState: nil, subject: .message(id: messageId, highlight: true), peekData: nil))) } } else { return .single(.inaccessiblePeer) From 5a0edd216272f262120dfc49a05cafc652cab18f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 26 Sep 2020 12:31:18 +0400 Subject: [PATCH 3/3] Comments [WIP] --- .../Sources/AnimatedCountLabelNode.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 33 ++++++---- .../Sources/ChatControllerNode.swift | 2 +- .../Sources/ChatHistoryListNode.swift | 8 +++ .../ChatRecentActionsHistoryTransition.swift | 64 +++++++++++++++---- .../TelegramUI/Sources/ChatTitleView.swift | 4 +- .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 2 +- 7 files changed, 88 insertions(+), 27 deletions(-) diff --git a/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift b/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift index e2c74740fa..bf51bd44de 100644 --- a/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift +++ b/submodules/AnimatedCountLabelNode/Sources/AnimatedCountLabelNode.swift @@ -135,7 +135,7 @@ public class AnimatedCountLabelNode: ASDisplayNode { textNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2) textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } - } else { + } else if textNode.frame != textFrame { transition.updateFrameAdditive(node: textNode, frame: textFrame) } currentOffset.x += layout.size.width diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 847a09c0d7..d6d04f5689 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -2195,7 +2195,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - strongSelf.openMessageReplies(messageId: messageId, isChannelPost: isChannelPost, atMessage: nil, displayModalProgress: displayModalProgress) + strongSelf.openMessageReplies(messageId: messageId, displayProgressInMessage: displayModalProgress ? nil : messageId, isChannelPost: isChannelPost, atMessage: nil, displayModalProgress: displayModalProgress) }, openReplyThreadOriginalMessage: { [weak self] message in guard let strongSelf = self else { return @@ -2211,7 +2211,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let attribute = attribute as? SourceReferenceMessageAttribute { if let threadMessageId = threadMessageId { if let _ = strongSelf.navigationController as? NavigationController { - strongSelf.openMessageReplies(messageId: threadMessageId, isChannelPost: true, atMessage: attribute.messageId, displayModalProgress: true) + strongSelf.openMessageReplies(messageId: threadMessageId, displayProgressInMessage: message.id, isChannelPost: true, atMessage: attribute.messageId, displayModalProgress: false) } } else { strongSelf.navigateToMessage(from: nil, to: .id(attribute.messageId)) @@ -3491,7 +3491,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }) - self.ready.set(combineLatest(self.chatDisplayNode.historyNode.historyState.get(), self._chatLocationInfoReady.get(), self.cachedDataReady.get(), initialData) |> map { _, chatLocationInfoReady, cachedDataReady, _ in + let effectiveCachedDataReady: Signal + if case .replyThread = self.chatLocation { + effectiveCachedDataReady = self.cachedDataReady.get() + } else { + effectiveCachedDataReady = .single(true) + } + self.ready.set(combineLatest(self.chatDisplayNode.historyNode.historyState.get(), self._chatLocationInfoReady.get(), effectiveCachedDataReady, initialData) |> map { _, chatLocationInfoReady, cachedDataReady, _ in return chatLocationInfoReady && cachedDataReady }) @@ -5402,6 +5408,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.historyNode.refreshPollActionsForVisibleMessages() } else { self.willAppear = true + + // Limit this to reply threads just to be safe now + if case .replyThread = self.chatLocation { + self.chatDisplayNode.historyNode.refocusOnUnreadMessagesIfNeeded() + } } if self.scheduledActivateInput { @@ -8329,12 +8340,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } - private func openMessageReplies(messageId: MessageId, isChannelPost: Bool, atMessage atMessageId: MessageId?, displayModalProgress: Bool) { + private func openMessageReplies(messageId: MessageId, displayProgressInMessage: MessageId?, isChannelPost: Bool, atMessage atMessageId: MessageId?, displayModalProgress: Bool) { guard let navigationController = self.navigationController as? NavigationController else { return } - if !displayModalProgress, self.controllerInteraction?.currentMessageWithLoadingReplyThread == messageId { + if let displayProgressInMessage = displayProgressInMessage, self.controllerInteraction?.currentMessageWithLoadingReplyThread == displayProgressInMessage { return } @@ -8343,12 +8354,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return EmptyDisposable } - if !displayModalProgress, controllerInteraction.currentMessageWithLoadingReplyThread != messageId { + if let displayProgressInMessage = displayProgressInMessage, controllerInteraction.currentMessageWithLoadingReplyThread != displayProgressInMessage { let previousId = controllerInteraction.currentMessageWithLoadingReplyThread - controllerInteraction.currentMessageWithLoadingReplyThread = messageId - strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(messageId) + controllerInteraction.currentMessageWithLoadingReplyThread = displayProgressInMessage + strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(displayProgressInMessage) if let previousId = previousId { - strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(previousId) + strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(displayProgressInMessage) } } @@ -8357,9 +8368,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction else { return } - if !displayModalProgress, controllerInteraction.currentMessageWithLoadingReplyThread == messageId { + if let displayProgressInMessage = displayProgressInMessage, controllerInteraction.currentMessageWithLoadingReplyThread == messageId { controllerInteraction.currentMessageWithLoadingReplyThread = nil - strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(messageId) + strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(displayProgressInMessage) } } } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index deae37c2e9..7de9a8402d 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -420,7 +420,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if isLoading != self.isLoadingValue { self.isLoadingValue = isLoading if isLoading { - self.historyNodeContainer.supernode?.insertSubnode(self.loadingNode, aboveSubnode: self.historyNodeContainer) + self.historyNodeContainer.supernode?.insertSubnode(self.loadingNode, belowSubnode: self.historyNodeContainer) self.loadingNode.layer.removeAllAnimations() self.loadingNode.alpha = 1.0 if animated { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index cb1c6ce36f..5408fe3285 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1108,6 +1108,14 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { self.updateVisibleItemRange(force: true) } + func refocusOnUnreadMessagesIfNeeded() { + self.forEachItemNode({ itemNode in + if let itemNode = itemNode as? ChatUnreadItemNode { + self.ensureItemNodeVisible(itemNode, animated: false, overflow: 0.0, curve: .Default(duration: nil)) + } + }) + } + private func processDisplayedItemRangeChanged(displayedRange: ListViewDisplayedItemRange, transactionState: ChatHistoryTransactionOpaqueState) { let historyView = transactionState.historyView var isTopReplyThreadMessageShownValue = false diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift index 42e7e08dd7..0dd763ed33 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsHistoryTransition.swift @@ -649,18 +649,60 @@ struct ChatRecentActionsEntry: Comparable, Identifiable { } else { var appendedRightsHeader = false - if case let .creator(_, _, prevRank) = prev.participant, case let .creator(_, _, newRank) = new.participant, prevRank != newRank { - appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in - var result: [MessageTextEntityType] = [] - if index == 0 { - result.append(.TextMention(peerId: new.peer.id)) - } else if index == 1 { - result.append(.Mention) - } else if index == 2 { - result.append(.Bold) + if case let .creator(_, prevAdminInfo, prevRank) = prev.participant, case let .creator(_, newAdminInfo, newRank) = new.participant, (prevRank != newRank || prevAdminInfo?.rights.flags.contains(.canBeAnonymous) != newAdminInfo?.rights.flags.contains(.canBeAnonymous)) { + if prevRank != newRank { + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessageRankName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), newRank ?? "") : self.presentationData.strings.Channel_AdminLog_MessageRankUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!, newRank ?? ""), generateEntities: { index in + var result: [MessageTextEntityType] = [] + if index == 0 { + result.append(.TextMention(peerId: new.peer.id)) + } else if index == 1 { + result.append(.Mention) + } else if index == 2 { + result.append(.Bold) + } + return result + }, to: &text, entities: &entities) + } + if prevAdminInfo?.rights.flags.contains(.canBeAnonymous) != newAdminInfo?.rights.flags.contains(.canBeAnonymous) { + let order: [(TelegramChatAdminRightsFlags, String)] + + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + order = [] + } else { + order = [ + (.canBeAnonymous, self.presentationData.strings.Channel_AdminLog_CanBeAnonymous) + ] } - return result - }, to: &text, entities: &entities) + + var appendedRightsHeader = false + for (flag, string) in order { + if prevAdminInfo?.rights.flags.contains(flag) != newAdminInfo?.rights.flags.contains(flag) { + if !appendedRightsHeader { + appendedRightsHeader = true + appendAttributedText(text: new.peer.addressName == nil ? self.presentationData.strings.Channel_AdminLog_MessagePromotedName(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)) : self.presentationData.strings.Channel_AdminLog_MessagePromotedNameUsername(new.peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), "@" + new.peer.addressName!), generateEntities: { index in + var result: [MessageTextEntityType] = [] + if index == 0 { + result.append(.TextMention(peerId: new.peer.id)) + } else if index == 1 { + result.append(.Mention) + } else if index == 2 { + result.append(.Bold) + } + return result + }, to: &text, entities: &entities) + text += "\n" + } + + text += "\n" + if prevAdminInfo?.rights.flags.contains(flag) != true { + text += "+" + } else { + text += "-" + } + appendAttributedText(text: string, withEntities: [.Italic], to: &text, entities: &entities) + } + } + } } else if case let .member(_, _, prevAdminRights, _, prevRank) = prev.participant { if case let .member(_, _, newAdminRights, _, newRank) = new.participant { let prevFlags = prevAdminRights?.rights.flags ?? [] diff --git a/submodules/TelegramUI/Sources/ChatTitleView.swift b/submodules/TelegramUI/Sources/ChatTitleView.swift index b847705db3..3baf18915c 100644 --- a/submodules/TelegramUI/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Sources/ChatTitleView.swift @@ -617,7 +617,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { if titleFrame.size.width < size.width { titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) } - transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) + transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame) } else { let combinedHeight = titleSize.height + activitySize.height + titleInfoSpacing @@ -626,7 +626,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { titleFrame.origin.x = -clearBounds.minX + floor((size.width - titleFrame.width) / 2.0) } titleFrame.origin.x = max(titleFrame.origin.x, clearBounds.minX + leftIconWidth) - transition.updateFrameAdditiveToCenter(node: self.titleNode, frame: titleFrame) + transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame) var activityFrame = CGRect(origin: CGPoint(x: floor((clearBounds.width - activitySize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + titleInfoSpacing), size: activitySize) if activitySize.width < size.width { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 8ff6a0bbde..cd6d5b2961 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -3308,7 +3308,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } } else { switch buttonKey { - case .mute, .search, .mute: + case .mute, .search, .videoCall: hiddenWhileExpanded = true default: hiddenWhileExpanded = false