From 08187e2d17a15b5c02077d8bc3de36882e570fc8 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 8 Mar 2023 17:41:21 +0400 Subject: [PATCH 1/3] Improve music albums display and playback order --- .../TelegramUI/Sources/ChatController.swift | 4 ++- .../Sources/ChatHistoryEntriesForView.swift | 27 ++++++++++++++++--- .../Sources/ChatHistoryListNode.swift | 15 ++++++----- .../OverlayAudioPlayerControllerNode.swift | 4 +-- .../PeerInfo/Panes/PeerInfoListPaneNode.swift | 2 +- .../Sources/PeerMessagesMediaPlaylist.swift | 19 ++++++++++--- 6 files changed, 54 insertions(+), 17 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index e8446f3402..049a52efc1 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -10272,7 +10272,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } strongSelf.presentAttachmentPremiumGift() - let _ = ApplicationSpecificNotice.incrementDismissedPremiumGiftSuggestion(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peerId).start() + Queue.mainQueue().after(0.5) { + let _ = ApplicationSpecificNotice.incrementDismissedPremiumGiftSuggestion(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peerId).start() + } }, requestLayout: { [weak self] transition in if let strongSelf = self, let layout = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, transition: transition) diff --git a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift index 953eaae337..0afc2f043e 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryEntriesForView.swift @@ -15,6 +15,7 @@ func chatHistoryEntriesForView( includeSearchEntry: Bool, reverse: Bool, groupMessages: Bool, + reverseGroupedMessages: Bool, selectedMessages: Set?, presentationData: ChatPresentationData, historyAppearsCleared: Bool, @@ -154,9 +155,18 @@ func chatHistoryEntriesForView( } } - if groupMessages { + if groupMessages || reverseGroupedMessages { if !groupBucket.isEmpty && message.groupInfo != groupBucket[0].0.groupInfo { - entries.append(.MessageGroupEntry(groupBucket[0].0.groupInfo!, groupBucket, presentationData)) + if reverseGroupedMessages { + groupBucket.reverse() + } + if groupMessages { + entries.append(.MessageGroupEntry(groupBucket[0].0.groupInfo!, groupBucket, presentationData)) + } else { + for (message, isRead, selection, attributes, location) in groupBucket { + entries.append(.MessageEntry(message, presentationData, isRead, location, selection, attributes)) + } + } groupBucket.removeAll() } if let _ = message.groupInfo { @@ -188,8 +198,17 @@ func chatHistoryEntriesForView( } if !groupBucket.isEmpty { - assert(groupMessages) - entries.append(.MessageGroupEntry(groupBucket[0].0.groupInfo!, groupBucket, presentationData)) + assert(groupMessages || reverseGroupedMessages) + if reverseGroupedMessages { + groupBucket.reverse() + } + if groupMessages { + entries.append(.MessageGroupEntry(groupBucket[0].0.groupInfo!, groupBucket, presentationData)) + } else { + for (message, isRead, selection, attributes, location) in groupBucket { + entries.append(.MessageEntry(message, presentationData, isRead, location, selection, attributes)) + } + } } if let maybeJoinMessage = joinMessage, !view.holeLater { diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 43db38fa4d..31ec565a7b 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -47,7 +47,7 @@ public enum ChatHistoryListDisplayHeaders { public enum ChatHistoryListMode: Equatable { case bubbles - case list(search: Bool, reversed: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool) + case list(search: Bool, reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool) } enum ChatHistoryViewScrollPosition { @@ -224,7 +224,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca switch mode { case .bubbles: item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location)) - case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch): + case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): let displayHeader: Bool switch displayHeaders { case .none: @@ -269,7 +269,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca switch mode { case .bubbles: item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location)) - case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch): + case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): let displayHeader: Bool switch displayHeaders { case .none: @@ -1216,10 +1216,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { var updatedScrollPosition = scrollPosition var reverse = false + var reverseGroups = false var includeSearchEntry = false - if case let .list(search, reverseValue, _, _, _) = mode { + if case let .list(search, reverseValue, reverseGroupsValue, _, _, _) = mode { includeSearchEntry = search reverse = reverseValue + reverseGroups = reverseGroupsValue } var isCopyProtectionEnabled: Bool = data.initialData?.peer?.isCopyProtectionEnabled ?? false @@ -1265,6 +1267,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { includeSearchEntry: includeSearchEntry && tagMask != nil, reverse: reverse, groupMessages: mode == .bubbles, + reverseGroupedMessages: reverseGroups, selectedMessages: selectedMessages, presentationData: chatPresentationData, historyAppearsCleared: historyAppearsCleared, @@ -3465,7 +3468,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { switch self.mode { case .bubbles: item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location)) - case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch): + case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): let displayHeader: Bool switch displayHeaders { case .none: @@ -3521,7 +3524,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { switch self.mode { case .bubbles: item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location)) - case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch): + case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch): let displayHeader: Bool switch displayHeaders { case .none: diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index cd49d9a72c..fe1088f646 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -208,7 +208,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu self.isGlobalSearch = false } - self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: true, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) self.historyNode.clipsToBounds = true super.init() @@ -550,7 +550,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu } let chatLocationContextHolder = Atomic(value: nil) - let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: true, timecode: nil), 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, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: true, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) historyNode.clipsToBounds = true historyNode.preloadPages = true historyNode.stackFromBottom = true diff --git a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift index f785e9da7d..a6575ab42b 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/Panes/PeerInfoListPaneNode.swift @@ -76,7 +76,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } self.selectedMessagesPromise.set(.single(self.selectedMessages)) - self.listNode = ChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false)) + self.listNode = ChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false)) self.listNode.clipsToBounds = true self.listNode.defaultToSynchronousTransactionWhileScrolling = true self.listNode.scroller.bounces = false diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift index a61a51613c..55d9f0ee29 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift @@ -264,10 +264,23 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M let message = view.entries[index + 1].message return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index + 1].index), true) } else { + var nextGroupingKey: Int64? for i in (0 ..< index).reversed() { - if view.entries[i].message.groupingKey != currentGroupKey { - let message = view.entries[i].message - return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[i].index), true) + if let nextGroupingKey { + if view.entries[i].message.groupingKey != nextGroupingKey { + let message = view.entries[i + 1].message + return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[i + 1].index), true) + } else if i == 0 { + let message = view.entries[i].message + return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[i].index), true) + } + } else if view.entries[i].message.groupingKey != currentGroupKey { + if let groupingKey = view.entries[i].message.groupingKey { + nextGroupingKey = groupingKey + } else { + let message = view.entries[i].message + return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[i].index), true) + } } } } From bcce69eb685516d838772ba8b382cdcafefc0df3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 8 Mar 2023 17:42:57 +0400 Subject: [PATCH 2/3] Add forward options when multiforwarding Fix message selection in forward preview --- .../Telegram-iOS/en.lproj/Localizable.strings | 5 + .../Sources/ChatController.swift | 6 +- .../TelegramUI/Sources/ChatController.swift | 100 +++--- .../Sources/ChatControllerNode.swift | 2 +- .../ChatMessageAnimatedStickerItemNode.swift | 9 +- .../Sources/PeerSelectionControllerNode.swift | 314 +++++++++++++++--- 6 files changed, 343 insertions(+), 93 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 23eb11f7a3..9985b8aaa9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9052,3 +9052,8 @@ Sorry for the inconvenience."; "Login.Email.PremiumRequiredText" = "Due to high cost of SMS in your country, you need to have a **Telegram Premium** account to reset this email via an SMS code. You can ask a friend to a gift a Premium subscription for your account %@"; "ChatList.StartMessaging" = "Select a chat to start messaging"; + +"Conversation.ForwardOptions.RecipientsMessageForwardVisible" = "Recipients will see that it was forwarded"; +"Conversation.ForwardOptions.RecipientsMessageForwardHidden" = "Recipients won't see that it was forwarded"; +"Conversation.ForwardOptions.RecipientsMessagesForwardVisible" = "Recipients will see they were forwarded"; +"Conversation.ForwardOptions.RecipientsMessagesForwardHidden" = "Recipients won't see they were forwarded"; diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index 2be2321fbf..61a80885d7 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -489,7 +489,7 @@ public enum ChatControllerSubject: Equatable { case message(id: MessageSubject, highlight: Bool, timecode: Double?) case scheduledMessages case pinnedMessages(id: EngineMessage.Id?) - case forwardedMessages(ids: [EngineMessage.Id], options: Signal) + case forwardedMessages(peerIds: [EnginePeer.Id], ids: [EngineMessage.Id], options: Signal) public static func ==(lhs: ChatControllerSubject, rhs: ChatControllerSubject) -> Bool { switch lhs { @@ -511,8 +511,8 @@ public enum ChatControllerSubject: Equatable { } else { return false } - case let .forwardedMessages(lhsIds, _): - if case let .forwardedMessages(rhsIds, _) = rhs, lhsIds == rhsIds { + case let .forwardedMessages(lhsPeerIds, lhsIds, _): + if case let .forwardedMessages(rhsPeerIds, rhsIds, _) = rhs, lhsPeerIds == rhsPeerIds, lhsIds == rhsIds { return true } else { return false diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 049a52efc1..752a2e7bed 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4606,7 +4606,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return message?.totalCount } |> distinctUntilChanged - } else if case let .forwardedMessages(messageIds, options) = subject { + } else if case let .forwardedMessages(peerIds, messageIds, options) = subject { displayedCountSignal = self.presentationInterfaceStatePromise.get() |> map { state -> Int? in if let selectionState = state.interfaceState.selectionState { @@ -4617,50 +4617,71 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } |> distinctUntilChanged - subtitleTextSignal = combineLatest(self.presentationInterfaceStatePromise.get(), options, displayedCountSignal) - |> map { state, options, count in - if let peer = state.renderedPeer?.chatMainPeer { - if let peer = peer as? TelegramUser { - let displayName = EnginePeer(peer).compactDisplayTitle - if count == 1 { - if options.hideNames { - return state.strings.Conversation_ForwardOptions_UserMessageForwardHidden(displayName).string + let peers = self.context.account.postbox.multiplePeersView(peerIds) + |> take(1) + + let presentationData = self.presentationData + subtitleTextSignal = combineLatest(peers, options, displayedCountSignal) + |> map { peersView, options, count in + let peers = peersView.peers.values + if !peers.isEmpty { + if peers.count == 1, let peer = peers.first { + if let peer = peer as? TelegramUser { + let displayName = EnginePeer(peer).compactDisplayTitle + if count == 1 { + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_UserMessageForwardHidden(displayName).string + } else { + return presentationData.strings.Conversation_ForwardOptions_UserMessageForwardVisible(displayName).string + } } else { - return state.strings.Conversation_ForwardOptions_UserMessageForwardVisible(displayName).string + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_UserMessagesForwardHidden(displayName).string + } else { + return presentationData.strings.Conversation_ForwardOptions_UserMessagesForwardVisible(displayName).string + } + } + } else if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + if count == 1 { + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_ChannelMessageForwardHidden + } else { + return presentationData.strings.Conversation_ForwardOptions_ChannelMessageForwardVisible + } + } else { + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_ChannelMessagesForwardHidden + } else { + return presentationData.strings.Conversation_ForwardOptions_ChannelMessagesForwardVisible + } } } else { - if options.hideNames { - return state.strings.Conversation_ForwardOptions_UserMessagesForwardHidden(displayName).string + if count == 1 { + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_GroupMessageForwardHidden + } else { + return presentationData.strings.Conversation_ForwardOptions_GroupMessageForwardVisible + } } else { - return state.strings.Conversation_ForwardOptions_UserMessagesForwardVisible(displayName).string - } - } - } else if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - if count == 1 { - if options.hideNames { - return state.strings.Conversation_ForwardOptions_ChannelMessageForwardHidden - } else { - return state.strings.Conversation_ForwardOptions_ChannelMessageForwardVisible - } - } else { - if options.hideNames { - return state.strings.Conversation_ForwardOptions_ChannelMessagesForwardHidden - } else { - return state.strings.Conversation_ForwardOptions_ChannelMessagesForwardVisible + if options.hideNames { + return presentationData.strings.Conversation_ForwardOptions_GroupMessagesForwardHidden + } else { + return presentationData.strings.Conversation_ForwardOptions_GroupMessagesForwardVisible + } } } } else { if count == 1 { if options.hideNames { - return state.strings.Conversation_ForwardOptions_GroupMessageForwardHidden + return presentationData.strings.Conversation_ForwardOptions_RecipientsMessageForwardHidden } else { - return state.strings.Conversation_ForwardOptions_GroupMessageForwardVisible + return presentationData.strings.Conversation_ForwardOptions_RecipientsMessageForwardVisible } } else { if options.hideNames { - return state.strings.Conversation_ForwardOptions_GroupMessagesForwardHidden + return presentationData.strings.Conversation_ForwardOptions_RecipientsMessagesForwardHidden } else { - return state.strings.Conversation_ForwardOptions_GroupMessagesForwardVisible + return presentationData.strings.Conversation_ForwardOptions_RecipientsMessagesForwardVisible } } } @@ -5948,6 +5969,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.chatTitleView?.networkState = state } }) + + if case let .forwardedMessages(_, messageIds, _) = self.subject, messageIds.count > 1 { + self.updateChatPresentationInterfaceState(interactive: false, { state in + return state.updatedInterfaceState({ $0.withUpdatedSelectedMessages(messageIds) }) + }) + } } required public init(coder aDecoder: NSCoder) { @@ -8100,7 +8127,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> distinctUntilChanged } - let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .forwardedMessages(ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions), botStart: nil, mode: .standard(previewing: true)) + let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .forwardedMessages(peerIds: [peerId], ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) let messageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] @@ -8132,7 +8159,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if !uniquePeerIds.contains(author.id) { uniquePeerIds.insert(author.id) } - if message.id.peerId == accountPeerId && message.forwardInfo == nil { } else { hasNotOwnMessages = true @@ -10635,12 +10661,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - if case let .forwardedMessages(messageIds, _) = self.subject, messageIds.count > 1 { - self.updateChatPresentationInterfaceState(interactive: false, { state in - return state.updatedInterfaceState({ $0.withUpdatedSelectedMessages(messageIds) }) - }) - } - self.displayNodeDidLoad() } @@ -18511,7 +18531,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent let sourceRect: CGRect? let navigationController: NavigationController? = nil - + let passthroughTouches: Bool init(controller: ViewController, sourceNode: ASDisplayNode?, sourceRect: CGRect? = nil, passthroughTouches: Bool) { diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index cf161a5fad..54aff54c94 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -336,7 +336,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.inputContextOverTextPanelContainer = ChatControllerTitlePanelNodeContainer() var source: ChatHistoryListSource - if case let .forwardedMessages(messageIds, options) = subject { + if case let .forwardedMessages(_, messageIds, options) = subject { let messages = combineLatest(context.account.postbox.messagesAtIds(messageIds), context.account.postbox.loadedPeerWithId(context.account.peerId), options) |> map { messages, accountPeer, options -> ([Message], Int32, Bool) in var messages = messages diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 54139e219f..4290a1aeb6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -640,7 +640,14 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } else if self.emojiFile?.id != emojiFile?.id { if self.emojiFile != nil { self.didSetUpAnimationNode = false - item.controllerInteraction.seenOneTimeAnimatedMedia.remove(item.message.id) + item.controllerInteraction.seenOneTimeAnimatedMedia.remove(item.message.id) + + self.animationNode?.removeFromSupernode() + self.animationNode = nil + + self.contextSourceNode.contentNode.insertSubnode(self.placeholderNode, aboveSubnode: self.imageNode) + + self.setupNode(item: item) } self.emojiFile = emojiFile if let emojiFile = emojiFile { diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index d357fced28..70f0e5c6e9 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -21,6 +21,7 @@ import MultiAnimationRenderer import AnimatedStickerNode import TelegramAnimatedStickerNode import SolidRoundedButtonNode +import ContextUI final class PeerSelectionControllerNode: ASDisplayNode { private let context: AccountContext @@ -36,13 +37,11 @@ final class PeerSelectionControllerNode: ASDisplayNode { private let requestPeerType: [ReplyMarkupButtonRequestPeerType]? private var presentationInterfaceState: ChatPresentationInterfaceState + private let presentationInterfaceStatePromise = ValuePromise() + private var interfaceInteraction: ChatPanelInterfaceInteraction? - var inProgress: Bool = false { - didSet { - - } - } + var inProgress: Bool = false var navigationBar: NavigationBar? @@ -125,7 +124,8 @@ final class PeerSelectionControllerNode: ASDisplayNode { self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(id: PeerId(0)), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil) - self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(forwardedMessageIds) } + self.presentationInterfaceState = self.presentationInterfaceState.updatedInterfaceState { $0.withUpdatedForwardMessageIds(forwardedMessageIds).withUpdatedForwardOptionsState(ChatInterfaceForwardOptionsState(hideNames: false, hideCaptions: false, unhideNamesOnCaptionChange: false)) } + self.presentationInterfaceStatePromise.set(self.presentationInterfaceState) if let _ = self.requestPeerType { self.requirementsBackgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.rootController.navigationBar.blurredBackgroundColor) @@ -346,7 +346,190 @@ final class PeerSelectionControllerNode: ASDisplayNode { if let strongSelf = self { strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardOptionsState($0.forwardOptionsState) }) }) } - }, presentForwardOptions: { _ in + }, presentForwardOptions: { [weak self] sourceNode in + guard let strongSelf = self else { + return + } + + let presentationData = strongSelf.presentationData + + let peerIds = strongSelf.selectedPeers.0.map { $0.id } + + let forwardOptions: Signal + forwardOptions = strongSelf.presentationInterfaceStatePromise.get() + |> map { state -> ChatControllerSubject.ForwardOptions in + return ChatControllerSubject.ForwardOptions(hideNames: state.interfaceState.forwardOptionsState?.hideNames ?? false, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false) + } + |> distinctUntilChanged + + let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: strongSelf.context.account.peerId), subject: .forwardedMessages(peerIds: peerIds, ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions), botStart: nil, mode: .standard(previewing: true)) + chatController.canReadHistory.set(false) + + let messageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] + let messagesCount: Signal + if let chatController = chatController as? ChatControllerImpl, messageIds.count > 1 { + messagesCount = .single(messageIds.count) + |> then( + chatController.presentationInterfaceStatePromise.get() + |> map { state -> Int in + return state.interfaceState.selectionState?.selectedIds.count ?? 1 + } + ) + } else { + messagesCount = .single(1) + } + + let accountPeerId = strongSelf.context.account.peerId + let items = combineLatest(forwardOptions, strongSelf.context.account.postbox.messagesAtIds(messageIds), messagesCount) + |> map { forwardOptions, messages, messagesCount -> [ContextMenuItem] in + var items: [ContextMenuItem] = [] + + var hasCaptions = false + var uniquePeerIds = Set() + + var hasOther = false + var hasNotOwnMessages = false + for message in messages { + if let author = message.effectiveAuthor { + if !uniquePeerIds.contains(author.id) { + uniquePeerIds.insert(author.id) + } + if message.id.peerId == accountPeerId && message.forwardInfo == nil { + } else { + hasNotOwnMessages = true + } + } + + var isDice = false + var isMusic = false + for media in message.media { + if let media = media as? TelegramMediaFile, media.isMusic { + isMusic = true + } else if media is TelegramMediaDice { + isDice = true + } else { + if !message.text.isEmpty { + if media is TelegramMediaImage || media is TelegramMediaFile { + hasCaptions = true + } + } + } + } + if !isDice && !isMusic { + hasOther = true + } + } + + let canHideNames = hasNotOwnMessages && hasOther + + let hideNames = forwardOptions.hideNames + let hideCaptions = forwardOptions.hideCaptions + + if !"".isEmpty { // check if seecret chat + } else { + if canHideNames { + items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in + if hideNames { + return nil + } else { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } + }, action: { [weak self] _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideNames = false + updated.hideCaptions = false + updated.unhideNamesOnCaptionChange = false + return updated + }) + }))) + + items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in + if hideNames { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } else { + return nil + } + }, action: { _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideNames = true + updated.unhideNamesOnCaptionChange = false + return updated + }) + }))) + + items.append(.separator) + } + + if hasCaptions { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in + if hideCaptions { + return nil + } else { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } + }, action: { [weak self] _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideCaptions = false + if updated.unhideNamesOnCaptionChange { + updated.unhideNamesOnCaptionChange = false + updated.hideNames = false + } + return updated + }) + }))) + + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in + if hideCaptions { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } else { + return nil + } + }, action: { _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideCaptions = true + if !updated.hideNames { + updated.hideNames = true + updated.unhideNamesOnCaptionChange = true + } + return updated + }) + }))) + + items.append(.separator) + } + } + + items.append(.action(ContextMenuActionItem(text: messagesCount == 1 ? presentationData.strings.Conversation_ForwardOptions_SendMessage : presentationData.strings.Conversation_ForwardOptions_SendMessages, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Resend"), color: theme.contextMenu.primaryColor) }, action: { [weak self, weak chatController] c, f in + guard let strongSelf = self else { + return + } + if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds { + var forwardMessageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] + forwardMessageIds = forwardMessageIds.filter { selectedMessageIds.contains($0) } + strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(forwardMessageIds) }) }) + } + strongSelf.textInputPanelNode?.sendMessage(.generic) + + f(.default) + }))) + + return items + } + + let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, passthroughTouches: true)), items: items |> map { ContextController.Items(content: .list($0)) }) + contextController.dismissedForCancel = { [weak chatController] in + if let selectedMessageIds = (chatController as? ChatControllerImpl)?.selectedMessageIds { + var forwardMessageIds = strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [] + forwardMessageIds = forwardMessageIds.filter { selectedMessageIds.contains($0) } + strongSelf.updateChatPresentationInterfaceState(animated: true, { $0.updatedInterfaceState({ $0.withUpdatedForwardMessageIds(forwardMessageIds) }) }) + } + } + contextController.immediateItemsTransitionAnimation = true + strongSelf.controller?.presentInGlobalOverlay(contextController) }, shareSelectedMessages: { }, updateTextInputStateAndMode: { [weak self] f in if let strongSelf = self { @@ -536,6 +719,7 @@ final class PeerSelectionControllerNode: ASDisplayNode { let updateInputTextState = self.presentationInterfaceState.interfaceState.effectiveInputState != presentationInterfaceState.interfaceState.effectiveInputState self.presentationInterfaceState = presentationInterfaceState + self.presentationInterfaceStatePromise.set(presentationInterfaceState) if let textInputPanelNode = self.textInputPanelNode, updateInputTextState { textInputPanelNode.updateInputTextState(presentationInterfaceState.interfaceState.effectiveInputState, animated: transition.isAnimated) @@ -546,6 +730,46 @@ final class PeerSelectionControllerNode: ASDisplayNode { } } + private var selectedPeers: ([Peer], [PeerId: Peer]) { + if self.contactListActive { + let selectedContactPeers = self.contactListNode?.selectedPeers ?? [] + + var selectedPeers: [Peer] = [] + var selectedPeerMap: [PeerId: Peer] = [:] + for contactPeer in selectedContactPeers { + if case let .peer(peer, _, _) = contactPeer { + selectedPeers.append(peer) + selectedPeerMap[peer.id] = peer + } + } + return (selectedPeers, selectedPeerMap) + } else { + var selectedPeerIds: [PeerId] = [] + var selectedPeerMap: [PeerId: Peer] = [:] + if let mainContainerNode = self.mainContainerNode { + mainContainerNode.currentItemNode.updateState { state in + selectedPeerIds = Array(state.selectedPeerIds) + selectedPeerMap = state.selectedPeerMap.mapValues({ $0._asPeer() }) + return state + } + } + if let chatListNode = self.chatListNode { + chatListNode.updateState { state in + selectedPeerIds = Array(state.selectedPeerIds) + selectedPeerMap = state.selectedPeerMap.mapValues({ $0._asPeer() }) + return state + } + } + var selectedPeers: [Peer] = [] + for peerId in selectedPeerIds { + if let peer = selectedPeerMap[peerId] { + selectedPeers.append(peer) + } + } + return (selectedPeers, selectedPeerMap) + } + } + func beginSelection() { if let _ = self.textInputPanelNode { } else { @@ -566,47 +790,9 @@ final class PeerSelectionControllerNode: ASDisplayNode { let effectiveInputText = strongSelf.presentationInterfaceState.interfaceState.composeInputState.inputText let forwardOptionsState = strongSelf.presentationInterfaceState.interfaceState.forwardOptionsState - if strongSelf.contactListActive { - strongSelf.contactListNode?.multipleSelection = true - let selectedContactPeers = strongSelf.contactListNode?.selectedPeers ?? [] - - var selectedPeers: [Peer] = [] - var selectedPeerMap: [PeerId: Peer] = [:] - for contactPeer in selectedContactPeers { - if case let .peer(peer, _, _) = contactPeer { - selectedPeers.append(peer) - selectedPeerMap[peer.id] = peer - } - } - if !selectedPeers.isEmpty { - strongSelf.requestSend?(selectedPeers, selectedPeerMap, effectiveInputText, mode, forwardOptionsState) - } - } else { - var selectedPeerIds: [PeerId] = [] - var selectedPeerMap: [PeerId: Peer] = [:] - if let mainContainerNode = strongSelf.mainContainerNode { - mainContainerNode.currentItemNode.updateState { state in - selectedPeerIds = Array(state.selectedPeerIds) - selectedPeerMap = state.selectedPeerMap.mapValues({ $0._asPeer() }) - return state - } - } - if let chatListNode = strongSelf.chatListNode { - chatListNode.updateState { state in - selectedPeerIds = Array(state.selectedPeerIds) - selectedPeerMap = state.selectedPeerMap.mapValues({ $0._asPeer() }) - return state - } - } - if !selectedPeerIds.isEmpty { - var selectedPeers: [Peer] = [] - for peerId in selectedPeerIds { - if let peer = selectedPeerMap[peerId] { - selectedPeers.append(peer) - } - } - strongSelf.requestSend?(selectedPeers, selectedPeerMap, effectiveInputText, mode, forwardOptionsState) - } + let (selectedPeers, selectedPeerMap) = strongSelf.selectedPeers + if !selectedPeers.isEmpty { + strongSelf.requestSend?(selectedPeers, selectedPeerMap, effectiveInputText, mode, forwardOptionsState) } } self.addSubnode(textInputPanelNode) @@ -1426,3 +1612,35 @@ private func stringForRequestPeerType(strings: PresentationStrings, peerType: Re return String(lines.joined(separator: "\n")) } } + +private final class ContextControllerContentSourceImpl: ContextControllerContentSource { + let controller: ViewController + weak var sourceNode: ASDisplayNode? + let sourceRect: CGRect? + + let navigationController: NavigationController? = nil + + let passthroughTouches: Bool + + init(controller: ViewController, sourceNode: ASDisplayNode?, sourceRect: CGRect? = nil, passthroughTouches: Bool) { + self.controller = controller + self.sourceNode = sourceNode + self.sourceRect = sourceRect + self.passthroughTouches = passthroughTouches + } + + func transitionInfo() -> ContextControllerTakeControllerInfo? { + let sourceNode = self.sourceNode + let sourceRect = self.sourceRect + return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in + if let sourceNode = sourceNode { + return (sourceNode.view, sourceRect ?? sourceNode.bounds) + } else { + return nil + } + }) + } + + func animatedIn() { + } +} From 838c352971dd8a75be5940a351eab0ff6a97c4c4 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 8 Mar 2023 18:10:20 +0400 Subject: [PATCH 3/3] More music album playback order improvements --- .../OverlayAudioPlayerControllerNode.swift | 4 ++-- .../Sources/PeerMessagesMediaPlaylist.swift | 22 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index fe1088f646..0cd80c9c25 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -208,7 +208,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu self.isGlobalSearch = false } - self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: true, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) self.historyNode.clipsToBounds = true super.init() @@ -550,7 +550,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu } let chatLocationContextHolder = Atomic(value: nil) - let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: true, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) + let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: true, timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) historyNode.clipsToBounds = true historyNode.preloadPages = true historyNode.stackFromBottom = true diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift index 55d9f0ee29..8cc15ce477 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift @@ -229,7 +229,7 @@ private func navigatedMessageFromMessages(_ messages: [Message], anchorIndex: Me } } -private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: MessageIndex, position: NavigatedMessageFromViewPosition) -> (message: Message, around: [Message], exact: Bool)? { +private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: MessageIndex, position: NavigatedMessageFromViewPosition, reversed: Bool) -> (message: Message, around: [Message], exact: Bool)? { var index = 0 for entry in view.entries { @@ -240,7 +240,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M case .exact: return (entry.message, aroundMessagesFromView(view: view, centralIndex: entry.index), true) case .later: - if let currentGroupKey { + if !reversed, let currentGroupKey { if index - 1 > 0, view.entries[index - 1].message.groupingKey == currentGroupKey { let message = view.entries[index - 1].message return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index - 1].index), true) @@ -259,7 +259,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M return nil } case .earlier: - if let currentGroupKey { + if !reversed, let currentGroupKey { if index + 1 < view.entries.count, view.entries[index + 1].message.groupingKey == currentGroupKey { let message = view.entries[index + 1].message return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index + 1].index), true) @@ -286,7 +286,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M } } else if index != 0 { let message = view.entries[index - 1].message - if let nextGroupingKey = message.groupingKey { + if !reversed, let nextGroupingKey = message.groupingKey { for i in (0 ..< index).reversed() { if view.entries[i].message.groupingKey != nextGroupingKey { let message = view.entries[i + 1].message @@ -410,7 +410,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { switch self.messagesLocation { case let .messages(_, _, messageId), let .singleMessage(messageId), let .custom(_, messageId, _): - self.loadItem(anchor: .messageId(messageId), navigation: .later) + self.loadItem(anchor: .messageId(messageId), navigation: .later, reversed: self.order == .reversed) case let .recentActions(message): self.loadingItem = false self.currentItem = (message, []) @@ -463,7 +463,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { self.currentItem = nil self.updateState() } else { - self.loadItem(anchor: .index(currentItem.current.index), navigation: navigation) + self.loadItem(anchor: .index(currentItem.current.index), navigation: navigation, reversed: self.order == .reversed) } } } @@ -524,7 +524,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } } - private func loadItem(anchor: PeerMessagesMediaPlaylistLoadAnchor, navigation: PeerMessagesMediaPlaylistNavigation) { + private func loadItem(anchor: PeerMessagesMediaPlaylistLoadAnchor, navigation: PeerMessagesMediaPlaylistNavigation, reversed: Bool) { self.loadingItem = true self.updateState() @@ -548,7 +548,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic(value: nil)), anchor: .index(message.index), ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: []) |> mapToSignal { view -> Signal<(Message, [Message])?, NoError> in - if let (message, aroundMessages, _) = navigatedMessageFromView(view.0, anchorIndex: message.index, position: .exact) { + if let (message, aroundMessages, _) = navigatedMessageFromView(view.0, anchorIndex: message.index, position: .exact, reversed: reversed) { return .single((message, aroundMessages)) } else { return .single((message, [])) @@ -670,7 +670,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { position = .exact } - if let (message, aroundMessages, exact) = navigatedMessageFromView(view.0, anchorIndex: inputIndex, position: position) { + if let (message, aroundMessages, exact) = navigatedMessageFromView(view.0, anchorIndex: inputIndex, position: position, reversed: reversed) { switch navigation { case .random: return .single((message, [])) @@ -697,7 +697,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { case .earlier: position = .later } - if let (message, aroundMessages, _) = navigatedMessageFromView(view.0, anchorIndex: MessageIndex.absoluteLowerBound(), position: position) { + if let (message, aroundMessages, _) = navigatedMessageFromView(view.0, anchorIndex: MessageIndex.absoluteLowerBound(), position: position, reversed: reversed) { return .single((message, aroundMessages)) } else { return .single(nil) @@ -832,7 +832,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } if messages.count > previousMessagesCount { - strongSelf.loadItem(anchor: anchor, navigation: navigation) + strongSelf.loadItem(anchor: anchor, navigation: navigation, reversed: strongSelf.order == .reversed) strongSelf.loadMoreDisposable.set(nil) strongSelf.loadingMore = false