mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
3206796f7c
31 changed files with 396 additions and 213 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ public enum InternalUpdaterError {
|
|||
public func requestUpdatesXml(account: Account, source: String) -> Signal<Data, InternalUpdaterError> {
|
||||
return TelegramEngine(account: account).peers.resolvePeerByName(name: source)
|
||||
|> castError(InternalUpdaterError.self)
|
||||
|> mapToSignal { peer -> Signal<Peer?, InternalUpdaterError> in
|
||||
return .single(peer?._asPeer())
|
||||
|> map { peer -> Peer? in
|
||||
return peer?._asPeer()
|
||||
}
|
||||
|> mapToSignal { peer in
|
||||
|> mapToSignal { peer -> Signal<Data, InternalUpdaterError> in
|
||||
if let peer = peer, let inputPeer = apiInputPeer(peer) {
|
||||
return account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: 0, addOffset: 0, limit: 1, maxId: Int32.max, minId: 0, hash: 0))
|
||||
|> retryRequest
|
||||
|> castError(InternalUpdaterError.self)
|
||||
|> mapToSignal { result in
|
||||
switch result {
|
||||
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
|
||||
case let .channelMessages(_, _, _, _, apiMessages, _, apiChats, apiUsers):
|
||||
if let apiMessage = apiMessages.first, let storeMessage = StoreMessage(apiMessage: apiMessage) {
|
||||
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
|
|
@ -67,7 +67,7 @@ public func requestUpdatesXml(account: Account, source: String) -> Signal<Data,
|
|||
} else {
|
||||
return .fail(.xmlLoad)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AppUpdateDownloadResult {
|
||||
|
|
@ -89,7 +89,7 @@ public func downloadAppUpdate(account: Account, source: String, messageId: Int32
|
|||
|> castError(InternalUpdaterError.self)
|
||||
|> mapToSignal { messages in
|
||||
switch messages {
|
||||
case let .channelMessages(_, _, _, _, apiMessages, apiChats, apiUsers):
|
||||
case let .channelMessages(_, _, _, _, apiMessages, _, apiChats, apiUsers):
|
||||
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
for chat in apiChats {
|
||||
|
|
|
|||
|
|
@ -848,7 +848,12 @@ func multipartFetch(postbox: Postbox, network: Network, mediaReferenceRevalidati
|
|||
} else {
|
||||
return .revalidate
|
||||
}
|
||||
case .messageAuthorAvatar:
|
||||
case let .messageAuthorAvatar(message, _):
|
||||
if let peer = message.author {
|
||||
if let location = resource.apiInputLocation(peerReference: peer) {
|
||||
return .location(location)
|
||||
}
|
||||
}
|
||||
return .revalidate
|
||||
default:
|
||||
return .none
|
||||
|
|
|
|||
|
|
@ -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 ([], [], [])
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -330,14 +331,14 @@ public final class AccountViewTracker {
|
|||
|
||||
private let externallyUpdatedPeerIdDisposable = MetaDisposable()
|
||||
|
||||
public let chatListPreloadItems = Promise<[ChatHistoryPreloadItem]>([])
|
||||
public let chatListPreloadItems = Promise<Set<ChatHistoryPreloadItem>>([])
|
||||
|
||||
init(account: Account) {
|
||||
self.account = account
|
||||
|
||||
self.historyViewStateValidationContexts = HistoryViewStateValidationContexts(queue: self.queue, postbox: account.postbox, network: account.network, accountPeerId: account.peerId)
|
||||
|
||||
self.chatHistoryPreloadManager = ChatHistoryPreloadManager(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, networkState: account.networkState, preloadItemsSignal: self.chatListPreloadItems.get() |> distinctUntilChanged)
|
||||
self.chatHistoryPreloadManager = ChatHistoryPreloadManager(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, networkState: account.networkState, preloadItemsSignal: self.chatListPreloadItems.get() |> distinctUntilChanged |> map { Array($0) })
|
||||
|
||||
self.externallyUpdatedPeerIdDisposable.set((account.stateManager.externallyUpdatedPeerIds
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] peerIds in
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -247,12 +247,19 @@ private final class AdditionalPreloadPeerIdsContext {
|
|||
}
|
||||
}
|
||||
|
||||
public struct ChatHistoryPreloadItem : Equatable {
|
||||
public struct ChatHistoryPreloadItem : Equatable, Hashable {
|
||||
public let index: ChatListIndex
|
||||
public let threadId: Int64?
|
||||
public let isMuted: Bool
|
||||
public let hasUnread: Bool
|
||||
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(index.hashValue)
|
||||
if let threadId = threadId {
|
||||
hasher.combine(threadId)
|
||||
}
|
||||
}
|
||||
|
||||
public init(index: ChatListIndex, threadId: Int64?, isMuted: Bool, hasUnread: Bool) {
|
||||
self.index = index
|
||||
self.threadId = threadId
|
||||
|
|
|
|||
|
|
@ -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, _, _):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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([])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -7,16 +7,24 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable {
|
|||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(peer, _, _, _, _):
|
||||
case let .message(peer, _, _, _, _, _):
|
||||
return peer
|
||||
}
|
||||
}
|
||||
public var author: PeerReference? {
|
||||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(_, author, _, _, _, _):
|
||||
return author
|
||||
}
|
||||
}
|
||||
|
||||
public var id: MessageId? {
|
||||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(_, id, _, _, _):
|
||||
case let .message(_, _, id, _, _, _):
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +33,7 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable {
|
|||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(_, _, timestamp, _, _):
|
||||
case let .message(_, _, _, timestamp, _, _):
|
||||
return timestamp
|
||||
}
|
||||
}
|
||||
|
|
@ -34,7 +42,7 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable {
|
|||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(_, _, _, incoming, _):
|
||||
case let .message(_, _, _, _, incoming, _):
|
||||
return incoming
|
||||
}
|
||||
}
|
||||
|
|
@ -43,22 +51,34 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable {
|
|||
switch content {
|
||||
case .none:
|
||||
return nil
|
||||
case let .message(_, _, _, _, secret):
|
||||
case let .message(_, _, _, _, _, secret):
|
||||
return secret
|
||||
}
|
||||
}
|
||||
|
||||
public init(_ message: Message) {
|
||||
if message.id.namespace != Namespaces.Message.Local, let peer = message.peers[message.id.peerId], let inputPeer = PeerReference(peer) {
|
||||
self.content = .message(peer: inputPeer, id: message.id, timestamp: message.timestamp, incoming: message.flags.contains(.Incoming), secret: message.containsSecretMedia)
|
||||
let author: PeerReference?
|
||||
if let peer = message.author {
|
||||
author = PeerReference(peer)
|
||||
} else {
|
||||
author = nil
|
||||
}
|
||||
self.content = .message(peer: inputPeer, author: author, id: message.id, timestamp: message.timestamp, incoming: message.flags.contains(.Incoming), secret: message.containsSecretMedia)
|
||||
} else {
|
||||
self.content = .none
|
||||
}
|
||||
}
|
||||
|
||||
public init(peer: Peer, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool) {
|
||||
public init(peer: Peer, author: Peer?, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool) {
|
||||
if let inputPeer = PeerReference(peer) {
|
||||
self.content = .message(peer: inputPeer, id: id, timestamp: timestamp, incoming: incoming, secret: secret)
|
||||
let a: PeerReference?
|
||||
if let peer = author {
|
||||
a = PeerReference(peer)
|
||||
} else {
|
||||
a = nil
|
||||
}
|
||||
self.content = .message(peer: inputPeer, author: a, id: id, timestamp: timestamp, incoming: incoming, secret: secret)
|
||||
} else {
|
||||
self.content = .none
|
||||
}
|
||||
|
|
@ -75,14 +95,14 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable {
|
|||
|
||||
public enum MessageReferenceContent: PostboxCoding, Hashable, Equatable {
|
||||
case none
|
||||
case message(peer: PeerReference, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool)
|
||||
case message(peer: PeerReference, author: PeerReference?, id: MessageId, timestamp: Int32, incoming: Bool, secret: Bool)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_r", orElse: 0) {
|
||||
case 0:
|
||||
self = .none
|
||||
case 1:
|
||||
self = .message(peer: decoder.decodeObjectForKey("p", decoder: { PeerReference(decoder: $0) }) as! PeerReference, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0)), timestamp: 0, incoming: false, secret: false)
|
||||
self = .message(peer: decoder.decodeObjectForKey("p", decoder: { PeerReference(decoder: $0) }) as! PeerReference, author: decoder.decodeObjectForKey("author") as? PeerReference, id: MessageId(peerId: PeerId(decoder.decodeInt64ForKey("i.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt32ForKey("i.i", orElse: 0)), timestamp: 0, incoming: false, secret: false)
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .none
|
||||
|
|
@ -93,9 +113,14 @@ public enum MessageReferenceContent: PostboxCoding, Hashable, Equatable {
|
|||
switch self {
|
||||
case .none:
|
||||
encoder.encodeInt32(0, forKey: "_r")
|
||||
case let .message(peer, id, _, _, _):
|
||||
case let .message(peer, author, id, _, _, _):
|
||||
encoder.encodeInt32(1, forKey: "_r")
|
||||
encoder.encodeObject(peer, forKey: "p")
|
||||
if let author = author {
|
||||
encoder.encodeObject(author, forKey: "author")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "author")
|
||||
}
|
||||
encoder.encodeInt64(id.peerId.toInt64(), forKey: "i.p")
|
||||
encoder.encodeInt32(id.namespace, forKey: "i.n")
|
||||
encoder.encodeInt32(id.id, forKey: "i.i")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ([], [], [])
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
@ -531,7 +533,7 @@ func _internal_downloadMessage(postbox: Postbox, network: Network, messageId: Me
|
|||
}
|
||||
|
||||
func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource, message: MessageReference) -> Signal<Message?, NoError> {
|
||||
guard case let .message(peer, id, _, _, _) = message.content else {
|
||||
guard case let .message(peer, _, id, _, _, _) = message.content else {
|
||||
return .single(nil)
|
||||
}
|
||||
let signal: Signal<Api.messages.Messages, MTRpcError>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -4078,19 +4078,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)
|
||||
|
|
@ -9869,9 +9877,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
|
||||
|
|
@ -9935,73 +9943,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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10454,6 +10425,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()
|
||||
|
|
@ -17632,33 +17606,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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -576,10 +576,12 @@ public final class OngoingGroupCallContext {
|
|||
|
||||
self.audioSessionActiveDisposable.set((audioSessionActive
|
||||
|> deliverOn(queue)).start(next: { [weak self] isActive in
|
||||
guard let self else {
|
||||
guard let `self` = self else {
|
||||
return
|
||||
}
|
||||
#if os(iOS)
|
||||
self.context.setManualAudioSessionIsActive(isActive)
|
||||
#endif
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -579,7 +579,9 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt
|
|||
}
|
||||
|
||||
func nativeSetIsAudioSessionActive(isActive: Bool) {
|
||||
#if os(iOS)
|
||||
self.setManualAudioSessionIsActive(isActive)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1482,7 +1484,7 @@ private final class CallSignalingConnectionManager {
|
|||
let connection = CallSignalingConnectionImpl(queue: queue, host: host, port: port, peerTag: self.peerTag, dataReceived: { data in
|
||||
dataReceived(data)
|
||||
}, isClosed: { [weak self] in
|
||||
guard let self else {
|
||||
guard let `self` = self else {
|
||||
return
|
||||
}
|
||||
self.handleConnectionFailed(id: id)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue