Topic improvements

This commit is contained in:
Ali 2022-11-08 11:14:41 +04:00
parent dbb4dc8e12
commit 45e50a68d7
25 changed files with 331 additions and 189 deletions

View file

@ -378,6 +378,16 @@ public enum ChatControllerActivateInput {
case entityInput
}
public struct ChatNavigationStackItem: Hashable {
public var peerId: EnginePeer.Id
public var threadId: Int64?
public init(peerId: EnginePeer.Id, threadId: Int64?) {
self.peerId = peerId
self.threadId = threadId
}
}
public final class NavigateToChatControllerParams {
public enum Location {
case peer(EnginePeer)
@ -434,12 +444,12 @@ public final class NavigateToChatControllerParams {
public let options: NavigationAnimationOptions
public let parentGroupId: PeerGroupId?
public let chatListFilter: Int32?
public let chatNavigationStack: [PeerId]
public let chatNavigationStack: [ChatNavigationStackItem]
public let changeColors: Bool
public let setupController: (ChatController) -> Void
public let completion: (ChatController) -> Void
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, completion: @escaping (ChatController) -> Void = { _ in }) {
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: Location, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: ChatControllerActivateInput? = nil, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, useBackAnimation: Bool = false, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, completion: @escaping (ChatController) -> Void = { _ in }) {
self.navigationController = navigationController
self.chatController = chatController
self.chatLocationContextHolder = chatLocationContextHolder

View file

@ -580,6 +580,14 @@ public enum ChatPresentationInputQueryResult: Equatable {
public let ChatControllerCount = Atomic<Int32>(value: 0)
public final class PeerInfoNavigationSourceTag {
public let peerId: EnginePeer.Id
public init(peerId: EnginePeer.Id) {
self.peerId = peerId
}
}
public protocol PeerInfoScreen: ViewController {
}

View file

@ -86,7 +86,18 @@ public func peerAvatarImageData(account: Account, peerReference: PeerReference?,
public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, size: CGSize, round: Bool = true, font: UIFont = avatarPlaceholderFont(size: 13.0), drawLetters: Bool = true, fullSize: Bool = false, blurred: Bool = false) -> Signal<UIImage?, NoError> {
let iconSignal: Signal<UIImage?, NoError>
if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.first, displayDimensions: size, clipStyle: round ? .round : .none, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
let clipStyle: AvatarNodeClipStyle
if round {
if case let .channel(channel) = peer, channel.flags.contains(.isForum) {
clipStyle = .roundedRect
} else {
clipStyle = .round
}
} else {
clipStyle = .none
}
if let signal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.first, displayDimensions: size, clipStyle: clipStyle, blurred: blurred, inset: 0.0, emptyColor: nil, synchronousLoad: fullSize) {
if fullSize, let fullSizeSignal = peerAvatarImage(account: account, peerReference: PeerReference(peer._asPeer()), authorOfMessage: nil, representation: peer.profileImageRepresentations.last, displayDimensions: size, emptyColor: nil, synchronousLoad: true) {
iconSignal = combineLatest(.single(nil) |> then(signal), .single(nil) |> then(fullSizeSignal))
|> mapToSignal { thumbnailImage, fullSizeImage -> Signal<UIImage?, NoError> in

View file

@ -419,6 +419,17 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
ChatListControllerImpl.openMoreMenu(context: self.context, peerId: peerId, sourceController: self, isViewingAsTopics: true, sourceView: sourceNode.view, gesture: gesture)
}
self.moreBarButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
/*self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId)
self.navigationBar?.allowsCustomTransition = { [weak self] in
guard let strongSelf = self else {
return false
}
if strongSelf.navigationBar?.userInfo == nil {
return false
}
return true
}*/
}
switch self.location {

View file

@ -1273,7 +1273,7 @@ public func openPostbox(basePath: String, seedConfiguration: SeedConfiguration,
#if DEBUG
//debugSaveState(basePath: basePath + "/db", name: "previous1")
debugRestoreState(basePath: basePath + "/db", name: "previous1")
//debugRestoreState(basePath: basePath + "/db", name: "previous1")
#endif
let startTime = CFAbsoluteTimeGetCurrent()

View file

@ -1029,7 +1029,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[649453030] = { return Api.messages.MessageEditData.parse_messageEditData($0) }
dict[834488621] = { return Api.messages.MessageReactionsList.parse_messageReactionsList($0) }
dict[-1228606141] = { return Api.messages.MessageViews.parse_messageViews($0) }
dict[1682413576] = { return Api.messages.Messages.parse_channelMessages($0) }
dict[-948520370] = { return Api.messages.Messages.parse_channelMessages($0) }
dict[-1938715001] = { return Api.messages.Messages.parse_messages($0) }
dict[1951620897] = { return Api.messages.Messages.parse_messagesNotModified($0) }
dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) }

View file

@ -1374,16 +1374,16 @@ public extension Api.messages {
}
public extension Api.messages {
enum Messages: TypeConstructorDescription {
case channelMessages(flags: Int32, pts: Int32, count: Int32, offsetIdOffset: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case channelMessages(flags: Int32, pts: Int32, count: Int32, offsetIdOffset: Int32?, messages: [Api.Message], topics: [Api.ForumTopic], chats: [Api.Chat], users: [Api.User])
case messages(messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
case messagesNotModified(count: Int32)
case messagesSlice(flags: Int32, count: Int32, nextRate: Int32?, offsetIdOffset: Int32?, messages: [Api.Message], chats: [Api.Chat], users: [Api.User])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let chats, let users):
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
if boxed {
buffer.appendInt32(1682413576)
buffer.appendInt32(-948520370)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt32(pts, buffer: buffer, boxed: false)
@ -1395,6 +1395,11 @@ public extension Api.messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(topics.count))
for item in topics {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(chats.count))
for item in chats {
item.serialize(buffer, true)
@ -1460,8 +1465,8 @@ public extension Api.messages {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let chats, let users):
return ("channelMessages", [("flags", String(describing: flags)), ("pts", String(describing: pts)), ("count", String(describing: count)), ("offsetIdOffset", String(describing: offsetIdOffset)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))])
case .channelMessages(let flags, let pts, let count, let offsetIdOffset, let messages, let topics, let chats, let users):
return ("channelMessages", [("flags", String(describing: flags)), ("pts", String(describing: pts)), ("count", String(describing: count)), ("offsetIdOffset", String(describing: offsetIdOffset)), ("messages", String(describing: messages)), ("topics", String(describing: topics)), ("chats", String(describing: chats)), ("users", String(describing: users))])
case .messages(let messages, let chats, let users):
return ("messages", [("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))])
case .messagesNotModified(let count):
@ -1484,13 +1489,17 @@ public extension Api.messages {
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self)
}
var _6: [Api.Chat]?
var _6: [Api.ForumTopic]?
if let _ = reader.readInt32() {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ForumTopic.self)
}
var _7: [Api.User]?
var _7: [Api.Chat]?
if let _ = reader.readInt32() {
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
}
var _8: [Api.User]?
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
@ -1499,8 +1508,9 @@ public extension Api.messages {
let _c5 = _5 != nil
let _c6 = _6 != nil
let _c7 = _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.messages.Messages.channelMessages(flags: _1!, pts: _2!, count: _3!, offsetIdOffset: _4, messages: _5!, chats: _6!, users: _7!)
let _c8 = _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.messages.Messages.channelMessages(flags: _1!, pts: _2!, count: _3!, offsetIdOffset: _4, messages: _5!, topics: _6!, chats: _7!, users: _8!)
}
else {
return nil

View file

@ -485,7 +485,13 @@ enum LoadMessageHistoryThreadsError {
func _internal_requestMessageHistoryThreads(accountPeerId: PeerId, postbox: Postbox, network: Network, peerId: PeerId, offsetIndex: StoredPeerThreadCombinedState.Index?, limit: Int) -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> {
let signal: Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> = postbox.transaction { transaction -> Api.InputChannel? in
return transaction.getPeer(peerId).flatMap(apiInputChannel)
guard let channel = transaction.getPeer(peerId) as? TelegramChannel else {
return nil
}
if !channel.flags.contains(.isForum) {
return nil
}
return apiInputChannel(channel)
}
|> castError(LoadMessageHistoryThreadsError.self)
|> mapToSignal { inputChannel -> Signal<LoadMessageHistoryThreadsResult, LoadMessageHistoryThreadsError> in

View file

@ -38,7 +38,7 @@ public func loadedPeerFromMessage(account: Account, peerId: PeerId, messageId: M
apiUsers = users
case let .messagesSlice(_, _, _, _, _, _, users):
apiUsers = users
case let .channelMessages(_, _, _, _, _, _, users):
case let .channelMessages(_, _, _, _, _, _, _, users):
apiUsers = users
case .messagesNotModified:
apiUsers = []

View file

@ -2086,7 +2086,8 @@ private func resolveAssociatedMessages(postbox: Postbox, network: Network, state
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, chats, users):
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
return (messages, chats, users)
case .messagesNotModified:
return ([], [], [])

View file

@ -93,8 +93,9 @@ private func fetchWebpage(account: Account, messageId: MessageId) -> Signal<Void
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case .messagesNotModified:
@ -1070,7 +1071,7 @@ public final class AccountViewTracker {
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, chats, users):
case let .channelMessages(_, _, _, _, messages, _, chats, users):
return (messages, chats, users)
case .messagesNotModified:
return ([], [], [])
@ -1712,7 +1713,9 @@ public final class AccountViewTracker {
|> mapToSignal { threadInfo -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in
if let threadInfo = threadInfo {
let anchor: HistoryViewInputAnchor
if threadInfo.incomingUnreadCount > 0 && tagMask == nil {
if threadInfo.maxIncomingReadId <= 1 {
anchor = .message(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: 1))
} else if threadInfo.incomingUnreadCount > 0 && tagMask == nil {
let customUnreadMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: threadInfo.maxIncomingReadId)
anchor = .message(customUnreadMessageId)
} else {

View file

@ -522,8 +522,9 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, pts, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, pts, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
channelPts = pts
@ -540,7 +541,8 @@ private func validateChannelMessagesBatch(postbox: Postbox, network: Network, ac
}
return validateBatch(postbox: postbox, network: network, transaction: transaction, accountPeerId: accountPeerId, tag: tag, historyState: historyState, signal: signal, previous: previous, messageNamespace: Namespaces.Message.Cloud)
} |> switchToLatest
}
|> switchToLatest
}
private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId, threadMessageId: Int32, tag: MessageTags?, messageIds: [MessageId]) -> Signal<Void, NoError> {
@ -589,8 +591,9 @@ private func validateReplyThreadMessagesBatch(postbox: Postbox, network: Network
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, pts, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, pts, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
channelPts = pts
@ -630,8 +633,9 @@ private func validateScheduledMessagesBatch(postbox: Postbox, network: Network,
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case .messagesNotModified:
@ -703,8 +707,9 @@ private func validateBatch(postbox: Postbox, network: Network, transaction: Tran
|> map { result -> Set<MessageId> in
let apiMessages: [Api.Message]
switch result {
case let .channelMessages(_, _, _, _, messages, _, _):
case let .channelMessages(_, _, _, _, messages, apiTopics, _, _):
apiMessages = messages
let _ = apiTopics
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, _, _, messages, _, _):
@ -951,8 +956,9 @@ private func validateReplyThreadBatch(postbox: Postbox, network: Network, transa
|> map { result -> Set<MessageId> in
let apiMessages: [Api.Message]
switch result {
case let .channelMessages(_, _, _, _, messages, _, _):
case let .channelMessages(_, _, _, _, messages, apiTopics, _, _):
apiMessages = messages
let _ = apiTopics
case let .messages(messages, _, _):
apiMessages = messages
case let .messagesSlice(_, _, _, _, messages, _, _):

View file

@ -143,7 +143,8 @@ private func withResolvedAssociatedMessages<T>(postbox: Postbox, source: FetchMe
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, chats, users):
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
return (messages, chats, users)
case .messagesNotModified:
return ([], [], [])
@ -575,8 +576,9 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, pts, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, pts, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
channelPts = pts
@ -829,8 +831,9 @@ func fetchCallListHole(network: Network, postbox: Postbox, accountPeerId: PeerId
messages = apiMessages
chats = apiChats
users = apiUsers
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case .messagesNotModified:

View file

@ -128,7 +128,7 @@ private func synchronizeMarkAllUnseen(transaction: Transaction, postbox: Postbox
switch result {
case let .messages(messages, _, _):
return .single(messages.compactMap({ $0.id() }))
case let .channelMessages(_, _, _, _, messages, _, _):
case let .channelMessages(_, _, _, _, messages, _, _, _):
return .single(messages.compactMap({ $0.id() }))
case .messagesNotModified:
return .single([])

View file

@ -47,7 +47,7 @@ private func dialogTopMessage(network: Network, postbox: Postbox, peerId: PeerId
}
let apiMessages: [Api.Message]
switch result {
case let .channelMessages(_, _, _, _, messages, _, _):
case let .channelMessages(_, _, _, _, messages, _, _, _):
apiMessages = messages
case let .messages(messages, _, _):
apiMessages = messages

View file

@ -905,11 +905,25 @@ public extension TelegramEngine.EngineData.Item {
}
}
public struct ThreadData: TelegramEngineDataItem, PostboxViewDataItem {
public struct ThreadData: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public struct Key: Hashable {
public var id: EnginePeer.Id
public var threadId: Int64
public init(id: EnginePeer.Id, threadId: Int64) {
self.id = id
self.threadId = threadId
}
}
public typealias Result = MessageHistoryThreadData?
fileprivate var id: EnginePeer.Id
fileprivate var threadId: Int64
public var mapKey: Key {
return Key(id: self.id, threadId: self.threadId)
}
public init(id: EnginePeer.Id, threadId: Int64) {
self.id = id

View file

@ -66,7 +66,8 @@ func _internal_getMessagesLoadIfNecessary(_ messageIds: [MessageId], postbox: Po
return (messages, chats, users)
case let .messagesSlice(_, _, _, _, messages, chats, users):
return (messages, chats, users)
case let .channelMessages(_, _, _, _, messages, chats, users):
case let .channelMessages(_, _, _, _, messages, apiTopics, chats, users):
let _ = apiTopics
return (messages, chats, users)
case .messagesNotModified:
return ([], [], [])

View file

@ -74,8 +74,9 @@ private func mergedState(transaction: Transaction, state: SearchMessagesPeerStat
let totalCount: Int32
let nextRate: Int32?
switch result {
case let .channelMessages(_, _, count, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, count, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
totalCount = count
@ -478,8 +479,9 @@ func _internal_downloadMessage(postbox: Postbox, network: Network, messageId: Me
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case let .messages(apiMessages, apiChats, apiUsers):
@ -562,8 +564,9 @@ func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource,
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, apiTopics, apiChats, apiUsers):
messages = apiMessages
let _ = apiTopics
chats = apiChats
users = apiUsers
case let .messages(apiMessages, apiChats, apiUsers):
@ -638,7 +641,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
switch result {
case let .messages(apiMessages, _, _):
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _):
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
messages = apiMessages
@ -668,7 +671,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
switch result {
case let .messages(apiMessages, _, _):
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _):
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
messages = apiMessages
@ -692,7 +695,7 @@ func _internal_searchMessageIdByTimestamp(account: Account, peerId: PeerId, thre
switch result {
case let .messages(apiMessages, _, _):
messages = apiMessages
case let .channelMessages(_, _, _, _, apiMessages, _, _):
case let .channelMessages(_, _, _, _, apiMessages, _, _, _):
messages = apiMessages
case let .messagesSlice(_, _, _, _, apiMessages, _, _):
messages = apiMessages

View file

@ -712,7 +712,7 @@ public final class SparseMessageList {
}
}
public final class SparseMessageScrollingContext {
/*public final class SparseMessageScrollingContext {
public struct State: Equatable {
public var totalCount: Int
public var minTimestamp: Int32
@ -762,7 +762,7 @@ public final class SparseMessageScrollingContext {
case let .messagesSlice(_, count, _, _, apiMessages, _, _):
messages = apiMessages
totalCount = Int(count)
case let .channelMessages(_, _, count, _, apiMessages, _, _):
case let .channelMessages(_, _, count, _, apiMessages, _, _, _):
messages = apiMessages
totalCount = Int(count)
case .messagesNotModified:
@ -815,7 +815,7 @@ public final class SparseMessageScrollingContext {
return Impl(queue: queue, account: account, peerId: peerId)
})
}
}
}*/
public final class SparseMessageCalendar {
private final class Impl {

View file

@ -293,9 +293,9 @@ public extension TelegramEngine {
return SparseMessageCalendar(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag)
}
public func sparseMessageScrollingContext(peerId: EnginePeer.Id) -> SparseMessageScrollingContext {
/*public func sparseMessageScrollingContext(peerId: EnginePeer.Id) -> SparseMessageScrollingContext {
return SparseMessageScrollingContext(account: self.account, peerId: peerId)
}
}*/
public func refreshMessageTagStats(peerId: EnginePeer.Id, threadId: Int64?, tags: [EngineMessage.Tags]) -> Signal<Never, NoError> {
let account = self.account
@ -325,7 +325,7 @@ public extension TelegramEngine {
switch result {
case let .messagesSlice(_, count, _, _, messages, _, _):
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case let .channelMessages(_, _, count, _, messages, _, _):
case let .channelMessages(_, _, count, _, messages, _, _, _):
return (count, messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)
case let .messages(messages, _, _):
return (Int32(messages.count), messages.first?.id(namespace: Namespaces.Message.Cloud)?.id)

View file

@ -79,7 +79,7 @@ func _internal_requestPeerPhotos(postbox: Postbox, network: Network, peerId: Pee
let chats: [Api.Chat]
let users: [Api.User]
switch result {
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
case let .channelMessages(_, _, _, _, apiMessages, _, apiChats, apiUsers):
messages = apiMessages
chats = apiChats
users = apiUsers

View file

@ -219,7 +219,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
public weak var parentController: ViewController?
private let currentChatListFilter: Int32?
private let chatNavigationStack: [PeerId]
private let chatNavigationStack: [ChatNavigationStackItem]
public var peekActions: ChatControllerPeekActions = .standard
private var didSetup3dTouch: Bool = false
@ -494,8 +494,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
override public var customNavigationData: CustomViewControllerNavigationData? {
get {
if case let .peer(peerId) = self.chatLocation {
return ChatControllerNavigationData(peerId: peerId)
if let peerId = self.chatLocation.peerId {
return ChatControllerNavigationData(peerId: peerId, threadId: self.chatLocation.threadId)
} else {
return nil
}
@ -534,7 +534,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return title
}
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = []) {
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [ChatNavigationStackItem] = []) {
let _ = ChatControllerCount.modify { value in
return value + 1
}
@ -4079,19 +4079,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.controllerInteraction = controllerInteraction
if case let .peer(peerId) = chatLocation, peerId != context.account.peerId {
switch subject {
case .pinnedMessages, .scheduledMessages, .forwardedMessages:
break
default:
self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId)
if chatLocation.threadId == nil {
if let peerId = chatLocation.peerId, peerId != context.account.peerId {
switch subject {
case .pinnedMessages, .scheduledMessages, .forwardedMessages:
break
default:
self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId)
}
}
}
self.navigationBar?.allowsCustomTransition = { [weak self] in
guard let strongSelf = self else {
return false
self.navigationBar?.allowsCustomTransition = { [weak self] in
guard let strongSelf = self else {
return false
}
if strongSelf.navigationBar?.userInfo == nil {
return false
}
if strongSelf.navigationBar?.contentNode != nil {
return false
}
return true
}
return strongSelf.navigationItem.rightBarButtonItem === strongSelf.chatInfoNavigationButton?.buttonItem
}
self.chatTitleView = ChatTitleView(context: self.context, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: controllerInteraction.presentationContext.animationCache, animationRenderer: controllerInteraction.presentationContext.animationRenderer)
@ -9870,9 +9878,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
var updatedChatNavigationStack = strongSelf.chatNavigationStack
updatedChatNavigationStack.removeAll(where: { $0 == peer.id})
if case let .peer(peerId) = strongSelf.chatLocation {
updatedChatNavigationStack.insert(peerId, at: 0)
updatedChatNavigationStack.removeAll(where: { $0 == ChatNavigationStackItem(peerId: peer.id, threadId: nil) })
if let peerId = strongSelf.chatLocation.peerId {
updatedChatNavigationStack.insert(ChatNavigationStackItem(peerId: peerId, threadId: strongSelf.chatLocation.threadId), at: 0)
}
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), animated: false, chatListFilter: nextFolderId, chatNavigationStack: updatedChatNavigationStack, completion: { nextController in
@ -9936,73 +9944,36 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
var chatNavigationStack: [PeerId] = self.chatNavigationStack
if case let .peer(peerId) = self.chatLocation, let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
chatNavigationStack.removeAll()
chatNavigationStack = summary.peerIds.filter({ $0 != peerId })
var chatNavigationStack: [ChatNavigationStackItem] = self.chatNavigationStack
if let peerId = self.chatLocation.peerId {
if let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
chatNavigationStack.removeAll()
chatNavigationStack = summary.peerNavigationItems.filter({ $0 != ChatNavigationStackItem(peerId: peerId, threadId: self.chatLocation.threadId) })
}
if let _ = self.chatLocation.threadId {
if !chatNavigationStack.contains(ChatNavigationStackItem(peerId: peerId, threadId: nil)) {
chatNavigationStack.append(ChatNavigationStackItem(peerId: peerId, threadId: nil))
}
}
}
if !chatNavigationStack.isEmpty {
self.chatDisplayNode.navigationBar?.backButtonNode.isGestureEnabled = true
self.chatDisplayNode.navigationBar?.backButtonNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self else {
guard let strongSelf = self, let backButtonNode = strongSelf.chatDisplayNode.navigationBar?.backButtonNode, let navigationController = strongSelf.effectiveNavigationController else {
gesture.cancel()
return
}
let _ = (strongSelf.context.engine.data.get(EngineDataList(
chatNavigationStack.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
))
|> deliverOnMainQueue).start(next: { peerList in
guard let strongSelf = self, let backButtonNode = strongSelf.chatDisplayNode.navigationBar?.backButtonNode else {
return
}
let peers = peerList.compactMap { $0 }
let avatarSize = CGSize(width: 28.0, height: 28.0)
var items: [ContextMenuItem] = []
for peer in peers {
let title: String
let iconSource: ContextMenuActionItemIconSource?
if peer.id == strongSelf.context.account.peerId {
title = strongSelf.presentationData.strings.DialogList_SavedMessages
iconSource = nil
} else {
title = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
iconSource = ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer, size: avatarSize))
}
let isSavedMessages = peer.id == strongSelf.context.account.peerId
items.append(.action(ContextMenuActionItem(text: title, icon: { _ in
if isSavedMessages {
return generateAvatarImage(size: avatarSize, icon: savedMessagesIcon, iconScale: 0.5, color: .blue)
}
return nil
}, iconSource: iconSource, action: { _, f in
f(.default)
guard let strongSelf = self, let navigationController = strongSelf.effectiveNavigationController else {
return
}
let nextFolderId: Int32? = strongSelf.currentChatListFilter
var updatedChatNavigationStack = strongSelf.chatNavigationStack
if let index = updatedChatNavigationStack.firstIndex(of: peer.id) {
updatedChatNavigationStack.removeSubrange(0 ..< (index + 1))
}
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), useBackAnimation: true, animated: true, chatListFilter: nextFolderId, chatNavigationStack: updatedChatNavigationStack, completion: { nextController in
let _ = nextController
}))
})))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceView: backButtonNode.view, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
})
let nextFolderId: Int32? = strongSelf.currentChatListFilter
PeerInfoScreenImpl.displayChatNavigationMenu(
context: strongSelf.context,
chatNavigationStack: chatNavigationStack,
nextFolderId: nextFolderId,
parentController: strongSelf,
backButtonView: backButtonNode.view,
navigationController: navigationController,
gesture: gesture
)
}
}
}
@ -10455,6 +10426,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
interfaceState = interfaceState.withUpdatedHistoryScrollState(scrollState)
}
interfaceState = interfaceState.withUpdatedInputLanguage(self.chatDisplayNode.currentTextInputLanguage)
if case .peer = self.chatLocation, let channel = self.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.flags.contains(.isForum) {
interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState())
}
let _ = ChatInterfaceState.update(engine: self.context.engine, peerId: peerId, threadId: threadId, { _ in
return interfaceState
}).start()
@ -17633,33 +17607,35 @@ func peerMessageSelectedReactions(context: AccountContext, message: Message) ->
final class ChatControllerNavigationData: CustomViewControllerNavigationData {
let peerId: PeerId
let threadId: Int64?
init(peerId: PeerId) {
init(peerId: PeerId, threadId: Int64?) {
self.peerId = peerId
self.threadId = threadId
}
func combine(summary: CustomViewControllerNavigationDataSummary?) -> CustomViewControllerNavigationDataSummary? {
if let summary = summary as? ChatControllerNavigationDataSummary {
return summary.adding(peerId: self.peerId)
return summary.adding(peerNavigationItem: ChatNavigationStackItem(peerId: self.peerId, threadId: threadId))
} else {
return ChatControllerNavigationDataSummary(peerIds: [self.peerId])
return ChatControllerNavigationDataSummary(peerNavigationItems: [ChatNavigationStackItem(peerId: self.peerId, threadId: threadId)])
}
}
}
final class ChatControllerNavigationDataSummary: CustomViewControllerNavigationDataSummary {
let peerIds: [PeerId]
let peerNavigationItems: [ChatNavigationStackItem]
init(peerIds: [PeerId]) {
self.peerIds = peerIds
init(peerNavigationItems: [ChatNavigationStackItem]) {
self.peerNavigationItems = peerNavigationItems
}
func adding(peerId: PeerId) -> ChatControllerNavigationDataSummary {
var peerIds = self.peerIds
if let index = peerIds.firstIndex(of: peerId) {
peerIds.removeSubrange(0 ... index)
func adding(peerNavigationItem: ChatNavigationStackItem) -> ChatControllerNavigationDataSummary {
var peerNavigationItems = self.peerNavigationItems
if let index = peerNavigationItems.firstIndex(of: peerNavigationItem) {
peerNavigationItems.removeSubrange(0 ... index)
}
peerIds.insert(peerId, at: 0)
return ChatControllerNavigationDataSummary(peerIds: peerIds)
peerNavigationItems.insert(peerNavigationItem, at: 0)
return ChatControllerNavigationDataSummary(peerNavigationItems: peerNavigationItems)
}
}

View file

@ -110,6 +110,12 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMess
canScrollToRead = false
}
if case let .replyThread(message) = chatLocation, message.isForumPost {
if case let .message(index) = view.anchorIndex {
scrollPosition = .index(index: .message(index), position: .top(0.0), directionHint: .Up, animated: false, highlight: false, displayLink: false)
}
}
if let maxReadIndex = view.maxReadIndex, tagMask == nil, canScrollToRead {
let aroundIndex = maxReadIndex
scrollPosition = .unread(index: maxReadIndex)

View file

@ -2536,7 +2536,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
var transitionSourceHeight: CGFloat = 0.0
var transitionFraction: CGFloat = 0.0
var transitionSourceAvatarFrame = CGRect()
var transitionSourceAvatarFrame: CGRect?
var transitionSourceTitleFrame = CGRect()
var transitionSourceSubtitleFrame = CGRect()
@ -2544,10 +2544,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let headerBackgroundColor: UIColor = presentationData.theme.list.blocksBackgroundColor
var effectiveSeparatorAlpha: CGFloat
if let navigationTransition = self.navigationTransition, let sourceAvatarNode = (navigationTransition.sourceNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode {
if let navigationTransition = self.navigationTransition {
transitionSourceHeight = navigationTransition.sourceNavigationBar.backgroundNode.bounds.height
transitionFraction = navigationTransition.fraction
transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view)
if let sourceAvatarNode = (navigationTransition.sourceNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode {
transitionSourceAvatarFrame = sourceAvatarNode.view.convert(sourceAvatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view)
}
transitionSourceTitleFrame = navigationTransition.sourceTitleFrame
transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame
@ -2761,7 +2764,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.usernameNode.accessibilityLabel = usernameString.string
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 13.0), size: CGSize(width: avatarSize, height: avatarSize))
let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY)
let avatarCenter: CGPoint
if let transitionSourceAvatarFrame = transitionSourceAvatarFrame {
avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY)
} else {
avatarCenter = avatarFrame.center
}
let titleSize = titleNodeLayout[TitleNodeStateRegular]!.size
let titleExpandedSize = titleNodeLayout[TitleNodeStateExpanded]!.size
@ -2893,7 +2901,11 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let avatarScale: CGFloat
let avatarOffset: CGFloat
if self.navigationTransition != nil {
avatarScale = ((1.0 - transitionFraction) * avatarFrame.width + transitionFraction * transitionSourceAvatarFrame.width) / avatarFrame.width
if let transitionSourceAvatarFrame = transitionSourceAvatarFrame {
avatarScale = ((1.0 - transitionFraction) * avatarFrame.width + transitionFraction * transitionSourceAvatarFrame.width) / avatarFrame.width
} else {
avatarScale = 1.0
}
avatarOffset = 0.0
} else {
avatarScale = 1.0 * (1.0 - titleCollapseFraction) + avatarMinScale * titleCollapseFraction
@ -2909,7 +2921,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isAvatarExpanded {
self.avatarListNode.listContainerNode.isHidden = false
if !transitionSourceAvatarFrame.width.isZero {
if let transitionSourceAvatarFrame = transitionSourceAvatarFrame {
transition.updateCornerRadius(node: self.avatarListNode.listContainerNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0)
transition.updateCornerRadius(node: self.avatarListNode.listContainerNode.controlsClippingNode, cornerRadius: transitionFraction * transitionSourceAvatarFrame.width / 2.0)
} else {
@ -2947,7 +2959,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isAvatarExpanded {
let expandedAvatarCenter = CGPoint(x: expandedAvatarListSize.width / 2.0, y: expandedAvatarListSize.height / 2.0 - contentOffset / 2.0)
apparentAvatarFrame = CGRect(origin: CGPoint(x: expandedAvatarCenter.x * (1.0 - transitionFraction) + transitionFraction * avatarCenter.x, y: expandedAvatarCenter.y * (1.0 - transitionFraction) + transitionFraction * avatarCenter.y), size: CGSize())
if !transitionSourceAvatarFrame.width.isZero {
if let transitionSourceAvatarFrame = transitionSourceAvatarFrame {
let expandedFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: expandedAvatarListSize)
controlsClippingFrame = CGRect(origin: CGPoint(x: transitionFraction * transitionSourceAvatarFrame.minX + (1.0 - transitionFraction) * expandedFrame.minX, y: transitionFraction * transitionSourceAvatarFrame.minY + (1.0 - transitionFraction) * expandedFrame.minY), size: CGSize(width: transitionFraction * transitionSourceAvatarFrame.width + (1.0 - transitionFraction) * expandedFrame.width, height: transitionFraction * transitionSourceAvatarFrame.height + (1.0 - transitionFraction) * expandedFrame.height))
} else {
@ -2963,7 +2975,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let avatarListContainerFrame: CGRect
let avatarListContainerScale: CGFloat
if self.isAvatarExpanded {
if !transitionSourceAvatarFrame.width.isZero {
if let transitionSourceAvatarFrame = transitionSourceAvatarFrame {
let neutralAvatarListContainerSize = expandedAvatarListSize
let avatarListContainerSize = CGSize(width: neutralAvatarListContainerSize.width * (1.0 - transitionFraction) + transitionSourceAvatarFrame.width * transitionFraction, height: neutralAvatarListContainerSize.height * (1.0 - transitionFraction) + transitionSourceAvatarFrame.height * transitionFraction)
avatarListContainerFrame = CGRect(origin: CGPoint(x: -avatarListContainerSize.width / 2.0, y: -avatarListContainerSize.height / 2.0), size: avatarListContainerSize)

View file

@ -8548,7 +8548,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
override public var customNavigationData: CustomViewControllerNavigationData? {
get {
if !self.isSettings {
return ChatControllerNavigationData(peerId: self.peerId)
return ChatControllerNavigationData(peerId: self.peerId, threadId: self.chatLocation.threadId)
} else {
return nil
}
@ -8760,7 +8760,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
}
if case .peer = self.chatLocation {
if self.chatLocation.peerId != nil {
self.navigationBar?.makeCustomTransitionNode = { [weak self] other, isInteractive in
guard let strongSelf = self else {
return nil
@ -8777,9 +8777,6 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
if isInteractive && strongSelf.controllerNode.headerNode.isAvatarExpanded {
return nil
}
if other.contentNode != nil {
return nil
}
if let allowsCustomTransition = other.allowsCustomTransition, !allowsCustomTransition() {
return nil
}
@ -8924,50 +8921,122 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
}
}
static func displayChatNavigationMenu(context: AccountContext, chatNavigationStack: [ChatNavigationStackItem], nextFolderId: Int32?, parentController: ViewController, backButtonView: UIView, navigationController: NavigationController, gesture: ContextGesture) {
let peerMap = EngineDataMap(
Set(chatNavigationStack.map(\.peerId)).map(TelegramEngine.EngineData.Item.Peer.Peer.init)
)
let threadDataMap = EngineDataMap(
Set(chatNavigationStack.filter { $0.threadId != nil }).map { TelegramEngine.EngineData.Item.Peer.ThreadData(id: $0.peerId, threadId: $0.threadId!) }
)
let _ = (context.engine.data.get(
peerMap,
threadDataMap
)
|> deliverOnMainQueue).start(next: { [weak parentController, weak backButtonView, weak navigationController] peerMap, threadDataMap in
guard let parentController, let backButtonView else {
return
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let avatarSize = CGSize(width: 28.0, height: 28.0)
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChatList_Tabs_AllChats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
}, action: { _, f in
f(.default)
navigationController?.popToRoot(animated: true)
})))
for item in chatNavigationStack {
guard let maybeItemPeer = peerMap[item.peerId], let itemPeer = maybeItemPeer else {
continue
}
let title: String
let iconSource: ContextMenuActionItemIconSource?
if let threadId = item.threadId {
guard let maybeThreadData = threadDataMap[TelegramEngine.EngineData.Item.Peer.ThreadData.Key(id: item.peerId, threadId: threadId)], let threadData = maybeThreadData else {
continue
}
title = threadData.info.title
iconSource = nil
} else {
if itemPeer.id == context.account.peerId {
title = presentationData.strings.DialogList_SavedMessages
iconSource = nil
} else {
title = itemPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
iconSource = ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: context.account, peer: itemPeer, size: avatarSize))
}
}
let isSavedMessages = itemPeer.id == context.account.peerId
items.append(.action(ContextMenuActionItem(text: title, icon: { _ in
if isSavedMessages {
return generateAvatarImage(size: avatarSize, icon: savedMessagesIcon, iconScale: 0.5, color: .blue)
}
return nil
}, iconSource: iconSource, action: { _, f in
f(.default)
guard let navigationController = navigationController else {
return
}
var updatedChatNavigationStack = chatNavigationStack
if let index = updatedChatNavigationStack.firstIndex(of: item) {
updatedChatNavigationStack.removeSubrange(0 ..< (index + 1))
}
let navigateChatLocation: NavigateToChatControllerParams.Location
if let threadId = item.threadId {
navigateChatLocation = .replyThread(ChatReplyThreadMessage(
messageId: MessageId(peerId: item.peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
))
} else {
navigateChatLocation = .peer(itemPeer)
}
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: navigateChatLocation, useBackAnimation: true, animated: true, chatListFilter: nextFolderId, chatNavigationStack: updatedChatNavigationStack, completion: { _ in
}))
})))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: parentController, sourceView: backButtonView, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
parentController.presentInGlobalOverlay(contextController)
})
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var chatNavigationStack: [PeerId] = []
var chatNavigationStack: [ChatNavigationStackItem] = []
if !self.isSettings, let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
chatNavigationStack.removeAll()
chatNavigationStack = summary.peerIds.filter({ $0 != peerId })
chatNavigationStack = summary.peerNavigationItems.filter({ $0 != ChatNavigationStackItem(peerId: self.peerId, threadId: self.chatLocation.threadId) })
}
if !chatNavigationStack.isEmpty {
self.navigationBar?.backButtonNode.isGestureEnabled = true
self.navigationBar?.backButtonNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self else {
guard let strongSelf = self, let backButtonNode = strongSelf.navigationBar?.backButtonNode, let navigationController = strongSelf.navigationController as? NavigationController else {
gesture.cancel()
return
}
let _ = (strongSelf.context.engine.data.get(EngineDataList(
chatNavigationStack.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
))
|> deliverOnMainQueue).start(next: { peerList in
guard let strongSelf = self, let backButtonNode = strongSelf.navigationBar?.backButtonNode else {
return
}
let peers = peerList.compactMap { $0 }
let avatarSize = CGSize(width: 28.0, height: 28.0)
var items: [ContextMenuItem] = []
for peer in peers {
items.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), icon: { _ in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: peer, size: avatarSize)), action: { _, f in
f(.default)
guard let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController else {
return
}
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), animated: true, completion: { _ in
}))
})))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceView: backButtonNode.view, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
})
PeerInfoScreenImpl.displayChatNavigationMenu(
context: strongSelf.context,
chatNavigationStack: chatNavigationStack,
nextFolderId: nil,
parentController: strongSelf,
backButtonView: backButtonNode.view,
navigationController: navigationController,
gesture: gesture
)
}
}
}
@ -9105,14 +9174,6 @@ private func getUserPeer(engine: TelegramEngine, peerId: EnginePeer.Id) -> Signa
}
}
final class PeerInfoNavigationSourceTag {
let peerId: PeerId
init(peerId: PeerId) {
self.peerId = peerId
}
}
private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavigationTransitionNode {
private let screenNode: PeerInfoScreenNode
private let presentationData: PresentationData
@ -9238,7 +9299,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
transition.updateAlpha(node: currentBackButton, alpha: (1.0 - fraction))
}
if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let _ = (bottomNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode)?.avatarNode, let (previousTitleContainerNode, previousTitleNode) = self.previousTitleNode, let (previousStatusContainerNode, previousStatusNode) = self.previousStatusNode {
if let previousTitleView = bottomNavigationBar.titleView as? ChatTitleView, let (previousTitleContainerNode, previousTitleNode) = self.previousTitleNode, let (previousStatusContainerNode, previousStatusNode) = self.previousStatusNode {
let previousTitleFrame = previousTitleView.titleContainerView.convert(previousTitleView.titleContainerView.bounds, to: bottomNavigationBar.view)
let previousStatusFrame = previousTitleView.activityNode.view.convert(previousTitleView.activityNode.bounds, to: bottomNavigationBar.view)