mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Commends update
This commit is contained in:
parent
68bd4529bb
commit
adbf2534b0
@ -38,6 +38,7 @@ public func openUserGeneratedUrl(context: AccountContext, url: String, concealed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> deliverOnMainQueue).start(next: { result in
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
|
progressDisposable.dispose()
|
||||||
openResolved(result)
|
openResolved(result)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -606,6 +606,16 @@ public final class AccountViewTracker {
|
|||||||
var maxMessageId: MessageId?
|
var maxMessageId: MessageId?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyMaxReadIncomingMessageIdForReplyInfo(id: MessageId, maxReadIncomingMessageId: MessageId) {
|
||||||
|
self.queue.async {
|
||||||
|
if var state = self.updatedViewCountMessageIdsAndTimestamps[id], var result = state.result {
|
||||||
|
result.maxReadIncomingMessageId = maxReadIncomingMessageId
|
||||||
|
state.result = result
|
||||||
|
self.updatedViewCountMessageIdsAndTimestamps[id] = state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func replyInfoForMessageId(_ id: MessageId) -> Signal<UpdatedMessageReplyInfo?, NoError> {
|
public func replyInfoForMessageId(_ id: MessageId) -> Signal<UpdatedMessageReplyInfo?, NoError> {
|
||||||
return Signal { [weak self] subscriber in
|
return Signal { [weak self] subscriber in
|
||||||
let state = self?.updatedViewCountMessageIdsAndTimestamps[id]
|
let state = self?.updatedViewCountMessageIdsAndTimestamps[id]
|
||||||
@ -1167,7 +1177,7 @@ public final class AccountViewTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func polledChannel(peerId: PeerId) -> Signal<Void, NoError> {
|
public func polledChannel(peerId: PeerId) -> Signal<Void, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
self.queue.async {
|
self.queue.async {
|
||||||
|
@ -4,6 +4,14 @@ import Postbox
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramApi
|
import TelegramApi
|
||||||
|
|
||||||
|
private struct DiscussionMessage {
|
||||||
|
public var messageId: MessageId
|
||||||
|
public var isChannelPost: Bool
|
||||||
|
public var maxMessage: MessageId?
|
||||||
|
public var maxReadIncomingMessageId: MessageId?
|
||||||
|
public var maxReadOutgoingMessageId: MessageId?
|
||||||
|
}
|
||||||
|
|
||||||
private class ReplyThreadHistoryContextImpl {
|
private class ReplyThreadHistoryContextImpl {
|
||||||
private let queue: Queue
|
private let queue: Queue
|
||||||
private let account: Account
|
private let account: Account
|
||||||
@ -41,6 +49,7 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
private var initialStateDisposable: Disposable?
|
private var initialStateDisposable: Disposable?
|
||||||
private var holesDisposable: Disposable?
|
private var holesDisposable: Disposable?
|
||||||
private var readStateDisposable: Disposable?
|
private var readStateDisposable: Disposable?
|
||||||
|
private var updateInitialStateDisposable: Disposable?
|
||||||
private let readDisposable = MetaDisposable()
|
private let readDisposable = MetaDisposable()
|
||||||
|
|
||||||
init(queue: Queue, account: Account, data: ChatReplyThreadMessage) {
|
init(queue: Queue, account: Account, data: ChatReplyThreadMessage) {
|
||||||
@ -108,12 +117,107 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
strongSelf.maxReadOutgoingMessageIdValue = MessageId(peerId: data.messageId.peerId, namespace: Namespaces.Message.Cloud, id: value)
|
strongSelf.maxReadOutgoingMessageIdValue = MessageId(peerId: data.messageId.peerId, namespace: Namespaces.Message.Cloud, id: value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let updateInitialState: Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> = account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
|
return transaction.getPeer(data.messageId.peerId).flatMap(apiInputPeer)
|
||||||
|
}
|
||||||
|
|> castError(FetchChannelReplyThreadMessageError.self)
|
||||||
|
|> mapToSignal { inputPeer -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
|
||||||
|
guard let inputPeer = inputPeer else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
return account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: data.messageId.id))
|
||||||
|
|> mapError { _ -> FetchChannelReplyThreadMessageError in
|
||||||
|
return .generic
|
||||||
|
}
|
||||||
|
|> mapToSignal { discussionMessage -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
|
||||||
|
return account.postbox.transaction { transaction -> Signal<DiscussionMessage, FetchChannelReplyThreadMessageError> in
|
||||||
|
switch discussionMessage {
|
||||||
|
case let .discussionMessage(_, messages, maxId, readInboxMaxId, readOutboxMaxId, chats, users):
|
||||||
|
let parsedMessages = messages.compactMap { message -> StoreMessage? in
|
||||||
|
StoreMessage(apiMessage: message)
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let topMessage = parsedMessages.last, let parsedIndex = topMessage.index else {
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var peers: [Peer] = []
|
||||||
|
var peerPresences: [PeerId: PeerPresence] = [:]
|
||||||
|
|
||||||
|
for chat in chats {
|
||||||
|
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
|
||||||
|
peers.append(groupOrChannel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for user in users {
|
||||||
|
let telegramUser = TelegramUser(user: user)
|
||||||
|
peers.append(telegramUser)
|
||||||
|
if let presence = TelegramUserPresence(apiUser: user) {
|
||||||
|
peerPresences[telegramUser.id] = presence
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = transaction.addMessages(parsedMessages, location: .Random)
|
||||||
|
|
||||||
|
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||||
|
return updated
|
||||||
|
})
|
||||||
|
|
||||||
|
updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences)
|
||||||
|
|
||||||
|
let resolvedMaxMessage: MessageId?
|
||||||
|
if let maxId = maxId {
|
||||||
|
resolvedMaxMessage = MessageId(
|
||||||
|
peerId: parsedIndex.id.peerId,
|
||||||
|
namespace: Namespaces.Message.Cloud,
|
||||||
|
id: maxId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
resolvedMaxMessage = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return .single(DiscussionMessage(
|
||||||
|
messageId: parsedIndex.id,
|
||||||
|
isChannelPost: true,
|
||||||
|
maxMessage: resolvedMaxMessage,
|
||||||
|
maxReadIncomingMessageId: readInboxMaxId.flatMap { readMaxId in
|
||||||
|
MessageId(peerId: parsedIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: readMaxId)
|
||||||
|
},
|
||||||
|
maxReadOutgoingMessageId: readOutboxMaxId.flatMap { readMaxId in
|
||||||
|
MessageId(peerId: parsedIndex.id.peerId, namespace: Namespaces.Message.Cloud, id: readMaxId)
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> castError(FetchChannelReplyThreadMessageError.self)
|
||||||
|
|> switchToLatest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.updateInitialStateDisposable = (updateInitialState
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] updatedData in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let maxReadOutgoingMessageId = updatedData.maxReadOutgoingMessageId {
|
||||||
|
if let current = strongSelf.maxReadOutgoingMessageIdValue {
|
||||||
|
if maxReadOutgoingMessageId > current {
|
||||||
|
strongSelf.maxReadOutgoingMessageIdValue = maxReadOutgoingMessageId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strongSelf.maxReadOutgoingMessageIdValue = maxReadOutgoingMessageId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.initialStateDisposable?.dispose()
|
self.initialStateDisposable?.dispose()
|
||||||
self.holesDisposable?.dispose()
|
self.holesDisposable?.dispose()
|
||||||
self.readDisposable.dispose()
|
self.readDisposable.dispose()
|
||||||
|
self.updateInitialStateDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCurrentHole(entry: MessageHistoryHolesViewEntry?) {
|
func setCurrentHole(entry: MessageHistoryHolesViewEntry?) {
|
||||||
@ -156,6 +260,8 @@ private class ReplyThreadHistoryContextImpl {
|
|||||||
for attribute in message.attributes {
|
for attribute in message.attributes {
|
||||||
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
if let attribute = attribute as? SourceReferenceMessageAttribute {
|
||||||
if let sourceMessage = transaction.getMessage(attribute.messageId) {
|
if let sourceMessage = transaction.getMessage(attribute.messageId) {
|
||||||
|
account.viewTracker.applyMaxReadIncomingMessageIdForReplyInfo(id: attribute.messageId, maxReadIncomingMessageId: messageIndex.id)
|
||||||
|
|
||||||
var updatedAttribute: ReplyThreadMessageAttribute?
|
var updatedAttribute: ReplyThreadMessageAttribute?
|
||||||
for i in 0 ..< sourceMessage.attributes.count {
|
for i in 0 ..< sourceMessage.attributes.count {
|
||||||
if let attribute = sourceMessage.attributes[i] as? ReplyThreadMessageAttribute {
|
if let attribute = sourceMessage.attributes[i] as? ReplyThreadMessageAttribute {
|
||||||
@ -289,7 +395,7 @@ public enum FetchChannelReplyThreadMessageError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageId) -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> {
|
public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageId, atMessageId: MessageId?) -> Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError> {
|
||||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||||
}
|
}
|
||||||
@ -302,14 +408,6 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
let replyInfo = Promise<AccountViewTracker.UpdatedMessageReplyInfo?>()
|
let replyInfo = Promise<AccountViewTracker.UpdatedMessageReplyInfo?>()
|
||||||
replyInfo.set(account.viewTracker.replyInfoForMessageId(messageId))
|
replyInfo.set(account.viewTracker.replyInfoForMessageId(messageId))
|
||||||
|
|
||||||
struct DiscussionMessage {
|
|
||||||
public var messageId: MessageId
|
|
||||||
public var isChannelPost: Bool
|
|
||||||
public var maxMessage: MessageId?
|
|
||||||
public var maxReadIncomingMessageId: MessageId?
|
|
||||||
public var maxReadOutgoingMessageId: MessageId?
|
|
||||||
}
|
|
||||||
|
|
||||||
let remoteDiscussionMessageSignal: Signal<DiscussionMessage?, NoError> = account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: messageId.id))
|
let remoteDiscussionMessageSignal: Signal<DiscussionMessage?, NoError> = account.network.request(Api.functions.messages.getDiscussionMessage(peer: inputPeer, msgId: messageId.id))
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<Api.messages.DiscussionMessage?, NoError> in
|
|> `catch` { _ -> Signal<Api.messages.DiscussionMessage?, NoError> in
|
||||||
@ -380,16 +478,12 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let discussionMessageSignal = (replyInfo.get()
|
let discussionMessageSignal = (replyInfo.get()
|
||||||
|
|> take(1)
|
||||||
|> mapToSignal { replyInfo -> Signal<DiscussionMessage?, NoError> in
|
|> mapToSignal { replyInfo -> Signal<DiscussionMessage?, NoError> in
|
||||||
guard let replyInfo = replyInfo else {
|
guard let replyInfo = replyInfo else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
return account.postbox.transaction { transaction -> DiscussionMessage? in
|
return account.postbox.transaction { transaction -> DiscussionMessage? in
|
||||||
let isParticipant = transaction.getPeerChatListIndex(replyInfo.commentsPeerId) != nil
|
|
||||||
|
|
||||||
guard isParticipant else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var foundDiscussionMessageId: MessageId?
|
var foundDiscussionMessageId: MessageId?
|
||||||
transaction.scanMessageAttributes(peerId: replyInfo.commentsPeerId, namespace: Namespaces.Message.Cloud, limit: 1000, { id, attributes in
|
transaction.scanMessageAttributes(peerId: replyInfo.commentsPeerId, namespace: Namespaces.Message.Cloud, limit: 1000, { id, attributes in
|
||||||
for attribute in attributes {
|
for attribute in attributes {
|
||||||
@ -428,7 +522,8 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
discussionMessage.set(discussionMessageSignal)
|
discussionMessage.set(discussionMessageSignal)
|
||||||
|
|
||||||
let preloadedHistoryPosition: Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> = replyInfo.get()
|
let preloadedHistoryPosition: Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> = replyInfo.get()
|
||||||
|> castError(FetchChannelReplyThreadMessageError.self)
|
|> take(1)
|
||||||
|
|> castError(FetchChannelReplyThreadMessageError.self)
|
||||||
|> mapToSignal { replyInfo -> Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> in
|
|> mapToSignal { replyInfo -> Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> in
|
||||||
if let replyInfo = replyInfo {
|
if let replyInfo = replyInfo {
|
||||||
return account.postbox.transaction { transaction -> (FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?) in
|
return account.postbox.transaction { transaction -> (FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?) in
|
||||||
@ -446,11 +541,12 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
return (threadInput, replyInfo.commentsPeerId, threadMessageId, replyInfo.maxReadIncomingMessageId, replyInfo.maxMessageId)
|
return (threadInput, replyInfo.commentsPeerId, threadMessageId, atMessageId ?? replyInfo.maxReadIncomingMessageId, replyInfo.maxMessageId)
|
||||||
}
|
}
|
||||||
|> castError(FetchChannelReplyThreadMessageError.self)
|
|> castError(FetchChannelReplyThreadMessageError.self)
|
||||||
} else {
|
} else {
|
||||||
return discussionMessage.get()
|
return discussionMessage.get()
|
||||||
|
|> take(1)
|
||||||
|> castError(FetchChannelReplyThreadMessageError.self)
|
|> castError(FetchChannelReplyThreadMessageError.self)
|
||||||
|> mapToSignal { discussionMessage -> Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> in
|
|> mapToSignal { discussionMessage -> Signal<(FetchMessageHistoryHoleThreadInput, PeerId, MessageId?, MessageId?, MessageId?), FetchChannelReplyThreadMessageError> in
|
||||||
guard let discussionMessage = discussionMessage else {
|
guard let discussionMessage = discussionMessage else {
|
||||||
@ -459,7 +555,7 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
|
|
||||||
let topMessageId = discussionMessage.messageId
|
let topMessageId = discussionMessage.messageId
|
||||||
let commentsPeerId = topMessageId.peerId
|
let commentsPeerId = topMessageId.peerId
|
||||||
return .single((.direct(peerId: commentsPeerId, threadId: makeMessageThreadId(topMessageId)), commentsPeerId, discussionMessage.messageId, discussionMessage.maxReadIncomingMessageId, discussionMessage.maxMessage))
|
return .single((.direct(peerId: commentsPeerId, threadId: makeMessageThreadId(topMessageId)), commentsPeerId, discussionMessage.messageId, atMessageId ?? discussionMessage.maxReadIncomingMessageId, discussionMessage.maxMessage))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,6 +618,7 @@ public func fetchChannelReplyThreadMessage(account: Account, messageId: MessageI
|
|||||||
|
|
||||||
return combineLatest(
|
return combineLatest(
|
||||||
discussionMessage.get()
|
discussionMessage.get()
|
||||||
|
|> take(1)
|
||||||
|> castError(FetchChannelReplyThreadMessageError.self),
|
|> castError(FetchChannelReplyThreadMessageError.self),
|
||||||
preloadedHistory
|
preloadedHistory
|
||||||
)
|
)
|
||||||
|
@ -539,14 +539,13 @@ func fetchRemoteMessage(postbox: Postbox, source: FetchMessageHistoryHoleSource,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timestamp: Int32) -> Signal<MessageId?, NoError> {
|
public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, threadId: Int64?, timestamp: Int32) -> Signal<MessageId?, NoError> {
|
||||||
return account.postbox.transaction { transaction -> Signal<MessageId?, NoError> in
|
return account.postbox.transaction { transaction -> Signal<MessageId?, NoError> in
|
||||||
if peerId.namespace == Namespaces.Peer.SecretChat {
|
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
return .single(transaction.findClosestMessageIdByTimestamp(peerId: peerId, timestamp: timestamp))
|
return .single(transaction.findClosestMessageIdByTimestamp(peerId: peerId, timestamp: timestamp))
|
||||||
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||||
var secondaryIndex: Signal<MessageIndex?, NoError> = .single(nil)
|
if let threadId = threadId {
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference, let secondaryPeer = transaction.getPeer(migrationReference.maxMessageId.peerId), let inputSecondaryPeer = apiInputPeer(secondaryPeer) {
|
let primaryIndex = account.network.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: makeThreadIdMessageId(peerId: peerId, threadId: threadId).id, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||||
secondaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputSecondaryPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
|
||||||
|> map { result -> MessageIndex? in
|
|> map { result -> MessageIndex? in
|
||||||
let messages: [Api.Message]
|
let messages: [Api.Message]
|
||||||
switch result {
|
switch result {
|
||||||
@ -569,45 +568,76 @@ public func searchMessageIdByTimestamp(account: Account, peerId: PeerId, timesta
|
|||||||
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
}
|
return primaryIndex
|
||||||
let primaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
|> map { primaryIndex -> MessageId? in
|
||||||
|> map { result -> MessageIndex? in
|
return primaryIndex?.id
|
||||||
let messages: [Api.Message]
|
|
||||||
switch result {
|
|
||||||
case let .messages(apiMessages, _, _):
|
|
||||||
messages = apiMessages
|
|
||||||
case let .channelMessages(_, _, _, apiMessages, _, _):
|
|
||||||
messages = apiMessages
|
|
||||||
case let .messagesSlice(_, _, _, apiMessages, _, _):
|
|
||||||
messages = apiMessages
|
|
||||||
case .messagesNotModified:
|
|
||||||
messages = []
|
|
||||||
}
|
}
|
||||||
for message in messages {
|
} else {
|
||||||
if let message = StoreMessage(apiMessage: message) {
|
var secondaryIndex: Signal<MessageIndex?, NoError> = .single(nil)
|
||||||
return message.index
|
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference, let secondaryPeer = transaction.getPeer(migrationReference.maxMessageId.peerId), let inputSecondaryPeer = apiInputPeer(secondaryPeer) {
|
||||||
|
secondaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputSecondaryPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||||
|
|> map { result -> MessageIndex? in
|
||||||
|
let messages: [Api.Message]
|
||||||
|
switch result {
|
||||||
|
case let .messages(apiMessages, _, _):
|
||||||
|
messages = apiMessages
|
||||||
|
case let .channelMessages(_, _, _, apiMessages, _, _):
|
||||||
|
messages = apiMessages
|
||||||
|
case let .messagesSlice(_, _, _, apiMessages, _, _):
|
||||||
|
messages = apiMessages
|
||||||
|
case .messagesNotModified:
|
||||||
|
messages = []
|
||||||
|
}
|
||||||
|
for message in messages {
|
||||||
|
if let message = StoreMessage(apiMessage: message) {
|
||||||
|
return message.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
let primaryIndex = account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: 0, offsetDate: timestamp, addOffset: -1, limit: 1, maxId: 0, minId: 0, hash: 0))
|
||||||
}
|
|> map { result -> MessageIndex? in
|
||||||
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|
let messages: [Api.Message]
|
||||||
return .single(nil)
|
switch result {
|
||||||
}
|
case let .messages(apiMessages, _, _):
|
||||||
return combineLatest(primaryIndex, secondaryIndex)
|
messages = apiMessages
|
||||||
|> map { primaryIndex, secondaryIndex -> MessageId? in
|
case let .channelMessages(_, _, _, apiMessages, _, _):
|
||||||
if let primaryIndex = primaryIndex, let secondaryIndex = secondaryIndex {
|
messages = apiMessages
|
||||||
if abs(primaryIndex.timestamp - timestamp) < abs(secondaryIndex.timestamp - timestamp) {
|
case let .messagesSlice(_, _, _, apiMessages, _, _):
|
||||||
return primaryIndex.id
|
messages = apiMessages
|
||||||
} else {
|
case .messagesNotModified:
|
||||||
return secondaryIndex.id
|
messages = []
|
||||||
|
}
|
||||||
|
for message in messages {
|
||||||
|
if let message = StoreMessage(apiMessage: message) {
|
||||||
|
return message.index
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if let primaryIndex = primaryIndex {
|
|
||||||
return primaryIndex.id
|
|
||||||
} else if let secondaryIndex = secondaryIndex {
|
|
||||||
return secondaryIndex.id
|
|
||||||
} else {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|> `catch` { _ -> Signal<MessageIndex?, NoError> in
|
||||||
|
return .single(nil)
|
||||||
|
}
|
||||||
|
return combineLatest(primaryIndex, secondaryIndex)
|
||||||
|
|> map { primaryIndex, secondaryIndex -> MessageId? in
|
||||||
|
if let primaryIndex = primaryIndex, let secondaryIndex = secondaryIndex {
|
||||||
|
if abs(primaryIndex.timestamp - timestamp) < abs(secondaryIndex.timestamp - timestamp) {
|
||||||
|
return primaryIndex.id
|
||||||
|
} else {
|
||||||
|
return secondaryIndex.id
|
||||||
|
}
|
||||||
|
} else if let primaryIndex = primaryIndex {
|
||||||
|
return primaryIndex.id
|
||||||
|
} else if let secondaryIndex = secondaryIndex {
|
||||||
|
return secondaryIndex.id
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
|
@ -2608,7 +2608,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if strongSelf.preloadHistoryPeerId != peerDiscussionId {
|
if strongSelf.preloadHistoryPeerId != peerDiscussionId {
|
||||||
strongSelf.preloadHistoryPeerId = peerDiscussionId
|
strongSelf.preloadHistoryPeerId = peerDiscussionId
|
||||||
if let peerDiscussionId = peerDiscussionId {
|
if let peerDiscussionId = peerDiscussionId {
|
||||||
strongSelf.preloadHistoryPeerIdDisposable.set(strongSelf.context.account.addAdditionalPreloadHistoryPeerId(peerId: peerDiscussionId))
|
let combinedDisposable = DisposableSet()
|
||||||
|
strongSelf.preloadHistoryPeerIdDisposable.set(combinedDisposable)
|
||||||
|
combinedDisposable.add(strongSelf.context.account.viewTracker.polledChannel(peerId: peerDiscussionId).start())
|
||||||
|
combinedDisposable.add(strongSelf.context.account.addAdditionalPreloadHistoryPeerId(peerId: peerDiscussionId))
|
||||||
} else {
|
} else {
|
||||||
strongSelf.preloadHistoryPeerIdDisposable.set(nil)
|
strongSelf.preloadHistoryPeerIdDisposable.set(nil)
|
||||||
}
|
}
|
||||||
@ -4257,7 +4260,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}, openCalendarSearch: { [weak self] in
|
}, openCalendarSearch: { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let peerId = strongSelf.chatLocation.peerId
|
|
||||||
strongSelf.chatDisplayNode.dismissInput()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
|
|
||||||
let controller = ChatDateSelectionSheet(presentationData: strongSelf.presentationData, completion: { timestamp in
|
let controller = ChatDateSelectionSheet(presentationData: strongSelf.presentationData, completion: { timestamp in
|
||||||
@ -4265,7 +4267,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.loadingMessage.set(true)
|
strongSelf.loadingMessage.set(true)
|
||||||
strongSelf.messageIndexDisposable.set((searchMessageIdByTimestamp(account: strongSelf.context.account, peerId: peerId, timestamp: timestamp) |> deliverOnMainQueue).start(next: { messageId in
|
|
||||||
|
let peerId: PeerId
|
||||||
|
let threadId: Int64?
|
||||||
|
switch strongSelf.chatLocation {
|
||||||
|
case let .peer(peerIdValue):
|
||||||
|
peerId = peerIdValue
|
||||||
|
threadId = nil
|
||||||
|
case let .replyThread(replyThreadMessage):
|
||||||
|
peerId = replyThreadMessage.messageId.peerId
|
||||||
|
threadId = makeMessageThreadId(replyThreadMessage.messageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.messageIndexDisposable.set((searchMessageIdByTimestamp(account: strongSelf.context.account, peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).start(next: { messageId in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.loadingMessage.set(false)
|
strongSelf.loadingMessage.set(false)
|
||||||
if let messageId = messageId {
|
if let messageId = messageId {
|
||||||
@ -5089,6 +5103,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
unarchiveAutomaticallyArchivedPeer(account: strongSelf.context.account, peerId: peerId)
|
unarchiveAutomaticallyArchivedPeer(account: strongSelf.context.account, peerId: peerId)
|
||||||
|
|
||||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .succeed(text: strongSelf.presentationData.strings.Conversation_UnarchiveDone), elevatedLayout: false, action: { _ in return false }), in: .current)
|
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .succeed(text: strongSelf.presentationData.strings.Conversation_UnarchiveDone), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||||
|
}, scrollToTop: { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.chatDisplayNode.historyNode.scrollToStartOfHistory()
|
||||||
}, viewReplies: { [weak self] sourceMessageId, replyThreadResult in
|
}, viewReplies: { [weak self] sourceMessageId, replyThreadResult in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -8202,7 +8222,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
progressDisposable.dispose()
|
progressDisposable.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] index in
|
|> deliverOnMainQueue).start(next: { index in
|
||||||
if index.1 {
|
if index.1 {
|
||||||
if !progressStarted {
|
if !progressStarted {
|
||||||
progressStarted = true
|
progressStarted = true
|
||||||
@ -8223,6 +8243,70 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func scrollToStartOfHistory() {
|
||||||
|
let locationInput = ChatHistoryLocationInput(content: .Scroll(index: .lowerBound, anchorIndex: .lowerBound, sourceIndex: .upperBound, scrollPosition: .bottom(0.0), animated: true), id: 0)
|
||||||
|
|
||||||
|
let historyView = preloadedChatHistoryViewForLocation(locationInput, context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, fixedCombinedReadStates: nil, tagMask: nil, additionalData: [])
|
||||||
|
let signal = historyView
|
||||||
|
|> mapToSignal { historyView -> Signal<(MessageIndex?, Bool), NoError> in
|
||||||
|
switch historyView {
|
||||||
|
case .Loading:
|
||||||
|
return .single((nil, true))
|
||||||
|
case .HistoryView:
|
||||||
|
return .single((nil, false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> take(until: { index in
|
||||||
|
return SignalTakeAction(passthrough: true, complete: !index.1)
|
||||||
|
})
|
||||||
|
|
||||||
|
var cancelImpl: (() -> Void)?
|
||||||
|
let presentationData = self.presentationData
|
||||||
|
let displayTime = CACurrentMediaTime()
|
||||||
|
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
||||||
|
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: {
|
||||||
|
if CACurrentMediaTime() - displayTime > 1.5 {
|
||||||
|
cancelImpl?()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
self?.present(controller, in: .window(.root))
|
||||||
|
return ActionDisposable { [weak controller] in
|
||||||
|
Queue.mainQueue().async() {
|
||||||
|
controller?.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> runOn(Queue.mainQueue())
|
||||||
|
|> delay(0.05, queue: Queue.mainQueue())
|
||||||
|
let progressDisposable = MetaDisposable()
|
||||||
|
var progressStarted = false
|
||||||
|
self.messageIndexDisposable.set((signal
|
||||||
|
|> afterDisposed {
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
progressDisposable.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { index in
|
||||||
|
if index.1 {
|
||||||
|
if !progressStarted {
|
||||||
|
progressStarted = true
|
||||||
|
progressDisposable.set(progressSignal.start())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, completed: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.loadingMessage.set(false)
|
||||||
|
strongSelf.chatDisplayNode.historyNode.scrollToStartOfHistory()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
cancelImpl = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.loadingMessage.set(false)
|
||||||
|
strongSelf.messageIndexDisposable.set(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateDownButtonVisibility() {
|
func updateDownButtonVisibility() {
|
||||||
let recordingMediaMessage = self.audioRecorderValue != nil || self.videoRecorderValue != nil
|
let recordingMediaMessage = self.audioRecorderValue != nil || self.videoRecorderValue != nil
|
||||||
self.chatDisplayNode.navigateButtons.displayDownButton = self.shouldDisplayDownButton && !recordingMediaMessage
|
self.chatDisplayNode.navigateButtons.displayDownButton = self.shouldDisplayDownButton && !recordingMediaMessage
|
||||||
@ -8280,13 +8364,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
static func openMessageReplies(context: AccountContext, navigationController: NavigationController, present: @escaping (ViewController, Any?) -> Void, messageId: MessageId, isChannelPost: Bool, atMessage atMessageId: MessageId?, displayModalProgress: Bool) -> Signal<Never, NoError> {
|
static func openMessageReplies(context: AccountContext, navigationController: NavigationController, present: @escaping (ViewController, Any?) -> Void, messageId: MessageId, isChannelPost: Bool, atMessage atMessageId: MessageId?, displayModalProgress: Bool) -> Signal<Never, NoError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let foundIndex = Promise<ReplyThreadInfo?>()
|
|
||||||
foundIndex.set(fetchAndPreloadReplyThreadInfo(context: context, subject: isChannelPost ? .channelPost(messageId) : .groupMessage(messageId))
|
|
||||||
|> map(Optional.init)
|
|
||||||
|> `catch` { _ -> Signal<ReplyThreadInfo?, NoError> in
|
|
||||||
return .single(nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
var cancelImpl: (() -> Void)?
|
var cancelImpl: (() -> Void)?
|
||||||
@ -8298,26 +8375,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
present(statusController, nil)
|
present(statusController, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let disposable = (foundIndex.get()
|
let disposable = (fetchAndPreloadReplyThreadInfo(context: context, subject: isChannelPost ? .channelPost(messageId) : .groupMessage(messageId), atMessageId: atMessageId)
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
|> deliverOnMainQueue).start(next: { [weak statusController] result in
|
||||||
if displayModalProgress {
|
if displayModalProgress {
|
||||||
statusController?.dismiss()
|
statusController?.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let result = result {
|
let chatLocation: ChatLocation = .replyThread(result.message)
|
||||||
let chatLocation: ChatLocation = .replyThread(result.message)
|
|
||||||
|
let subject: ChatControllerSubject?
|
||||||
let subject: ChatControllerSubject?
|
if let atMessageId = atMessageId {
|
||||||
if let atMessageId = atMessageId {
|
subject = .message(atMessageId)
|
||||||
subject = .message(atMessageId)
|
} else {
|
||||||
} else {
|
subject = nil
|
||||||
subject = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: chatLocation, chatLocationContextHolder: result.contextHolder, subject: subject, activateInput: result.isEmpty, keepStack: .always))
|
|
||||||
subscriber.putCompletion()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: chatLocation, chatLocationContextHolder: result.contextHolder, subject: subject, activateInput: result.isEmpty, keepStack: .always))
|
||||||
|
subscriber.putCompletion()
|
||||||
|
}, error: { _ in
|
||||||
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
|
present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
cancelImpl = { [weak statusController] in
|
cancelImpl = { [weak statusController] in
|
||||||
|
@ -302,24 +302,34 @@ enum ReplyThreadSubject {
|
|||||||
case groupMessage(MessageId)
|
case groupMessage(MessageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThreadSubject) -> Signal<ReplyThreadInfo, FetchChannelReplyThreadMessageError> {
|
func fetchAndPreloadReplyThreadInfo(context: AccountContext, subject: ReplyThreadSubject, atMessageId: MessageId?) -> Signal<ReplyThreadInfo, FetchChannelReplyThreadMessageError> {
|
||||||
let message: Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError>
|
let message: Signal<ChatReplyThreadMessage, FetchChannelReplyThreadMessageError>
|
||||||
switch subject {
|
switch subject {
|
||||||
case let .channelPost(messageId):
|
case let .channelPost(messageId):
|
||||||
message = fetchChannelReplyThreadMessage(account: context.account, messageId: messageId)
|
message = fetchChannelReplyThreadMessage(account: context.account, messageId: messageId, atMessageId: atMessageId)
|
||||||
case let .groupMessage(messageId):
|
case let .groupMessage(messageId):
|
||||||
message = fetchChannelReplyThreadMessage(account: context.account, messageId: messageId)
|
message = fetchChannelReplyThreadMessage(account: context.account, messageId: messageId, atMessageId: atMessageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|> mapToSignal { replyThreadMessage -> Signal<ReplyThreadInfo, FetchChannelReplyThreadMessageError> in
|
|> mapToSignal { replyThreadMessage -> Signal<ReplyThreadInfo, FetchChannelReplyThreadMessageError> in
|
||||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||||
|
|
||||||
let preloadSignal = preloadedChatHistoryViewForLocation(
|
let input: ChatHistoryLocationInput
|
||||||
ChatHistoryLocationInput(
|
if let atMessageId = atMessageId {
|
||||||
content: .Initial(count: 60),
|
input = ChatHistoryLocationInput(
|
||||||
|
content: .InitialSearch(location: .id(atMessageId), count: 30),
|
||||||
id: 0
|
id: 0
|
||||||
),
|
)
|
||||||
|
} else {
|
||||||
|
input = ChatHistoryLocationInput(
|
||||||
|
content: .Initial(count: 30),
|
||||||
|
id: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let preloadSignal = preloadedChatHistoryViewForLocation(
|
||||||
|
input,
|
||||||
context: context,
|
context: context,
|
||||||
chatLocation: .replyThread(replyThreadMessage),
|
chatLocation: .replyThread(replyThreadMessage),
|
||||||
chatLocationContextHolder: chatLocationContextHolder,
|
chatLocationContextHolder: chatLocationContextHolder,
|
||||||
|
@ -615,7 +615,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
|||||||
}, action: { c, _ in
|
}, action: { c, _ in
|
||||||
let foundIndex = Promise<ChatReplyThreadMessage?>()
|
let foundIndex = Promise<ChatReplyThreadMessage?>()
|
||||||
if let channel = messages[0].peers[messages[0].id.peerId] as? TelegramChannel {
|
if let channel = messages[0].peers[messages[0].id.peerId] as? TelegramChannel {
|
||||||
foundIndex.set(fetchChannelReplyThreadMessage(account: context.account, messageId: messages[0].id)
|
foundIndex.set(fetchChannelReplyThreadMessage(account: context.account, messageId: messages[0].id, atMessageId: nil)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
|
@ -676,7 +676,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
edited = true
|
edited = true
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -271,7 +271,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.statusNode)
|
self.addSubnode(self.statusNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ title: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ constrainedSize: CGSize) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
|
func asyncLayout() -> (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ chatLocation: ChatLocation, _ title: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ constrainedSize: CGSize) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
|
||||||
let textAsyncLayout = TextNode.asyncLayout(self.textNode)
|
let textAsyncLayout = TextNode.asyncLayout(self.textNode)
|
||||||
let currentImage = self.media as? TelegramMediaImage
|
let currentImage = self.media as? TelegramMediaImage
|
||||||
let imageLayout = self.inlineImageNode.asyncLayout()
|
let imageLayout = self.inlineImageNode.asyncLayout()
|
||||||
@ -284,7 +284,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
|
|
||||||
let currentAdditionalImageBadgeNode = self.additionalImageBadgeNode
|
let currentAdditionalImageBadgeNode = self.additionalImageBadgeNode
|
||||||
|
|
||||||
return { presentationData, automaticDownloadSettings, associatedData, attributes, context, controllerInteraction, message, messageRead, title, subtitle, text, entities, mediaAndFlags, mediaBadge, actionIcon, actionTitle, displayLine, layoutConstants, constrainedSize in
|
return { presentationData, automaticDownloadSettings, associatedData, attributes, context, controllerInteraction, message, messageRead, chatLocation, title, subtitle, text, entities, mediaAndFlags, mediaBadge, actionIcon, actionTitle, displayLine, layoutConstants, constrainedSize in
|
||||||
let isPreview = presentationData.isPreview
|
let isPreview = presentationData.isPreview
|
||||||
let fontSize: CGFloat = floor(presentationData.fontSize.baseDisplaySize * 15.0 / 17.0)
|
let fontSize: CGFloat = floor(presentationData.fontSize.baseDisplaySize * 15.0 / 17.0)
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = chatLocation {
|
||||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
@ -424,7 +424,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
} else if file.isInstantVideo {
|
} else if file.isInstantVideo {
|
||||||
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file)
|
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file)
|
||||||
let (videoLayout, apply) = contentInstantVideoLayout(ChatMessageBubbleContentItem(context: context, controllerInteraction: controllerInteraction, message: message, read: messageRead, presentationData: presentationData, associatedData: associatedData, attributes: attributes), constrainedSize.width - horizontalInsets.left - horizontalInsets.right, CGSize(width: 212.0, height: 212.0), .bubble, automaticDownload)
|
let (videoLayout, apply) = contentInstantVideoLayout(ChatMessageBubbleContentItem(context: context, controllerInteraction: controllerInteraction, message: message, read: messageRead, chatLocation: chatLocation, presentationData: presentationData, associatedData: associatedData, attributes: attributes), constrainedSize.width - horizontalInsets.left - horizontalInsets.right, CGSize(width: 212.0, height: 212.0), .bubble, automaticDownload)
|
||||||
initialWidth = videoLayout.contentSize.width + videoLayout.overflowLeft + videoLayout.overflowRight
|
initialWidth = videoLayout.contentSize.width + videoLayout.overflowLeft + videoLayout.overflowRight
|
||||||
contentInstantVideoSizeAndApply = (videoLayout, apply)
|
contentInstantVideoSizeAndApply = (videoLayout, apply)
|
||||||
} else if file.isVideo {
|
} else if file.isVideo {
|
||||||
@ -474,7 +474,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, refineLayout) = contentFileLayout(context, presentationData, message, attributes, file, automaticDownload, message.effectivelyIncoming(context.account.peerId), false, associatedData.forcedResourceStatus, statusType, CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height))
|
let (_, refineLayout) = contentFileLayout(context, presentationData, message, chatLocation, attributes, file, automaticDownload, message.effectivelyIncoming(context.account.peerId), false, associatedData.forcedResourceStatus, statusType, CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height))
|
||||||
refineContentFileLayout = refineLayout
|
refineContentFileLayout = refineLayout
|
||||||
}
|
}
|
||||||
} else if let image = media as? TelegramMediaImage {
|
} else if let image = media as? TelegramMediaImage {
|
||||||
|
@ -98,15 +98,17 @@ final class ChatMessageBubbleContentItem {
|
|||||||
let controllerInteraction: ChatControllerInteraction
|
let controllerInteraction: ChatControllerInteraction
|
||||||
let message: Message
|
let message: Message
|
||||||
let read: Bool
|
let read: Bool
|
||||||
|
let chatLocation: ChatLocation
|
||||||
let presentationData: ChatPresentationData
|
let presentationData: ChatPresentationData
|
||||||
let associatedData: ChatMessageItemAssociatedData
|
let associatedData: ChatMessageItemAssociatedData
|
||||||
let attributes: ChatMessageEntryAttributes
|
let attributes: ChatMessageEntryAttributes
|
||||||
|
|
||||||
init(context: AccountContext, controllerInteraction: ChatControllerInteraction, message: Message, read: Bool, presentationData: ChatPresentationData, associatedData: ChatMessageItemAssociatedData, attributes: ChatMessageEntryAttributes) {
|
init(context: AccountContext, controllerInteraction: ChatControllerInteraction, message: Message, read: Bool, chatLocation: ChatLocation, presentationData: ChatPresentationData, associatedData: ChatMessageItemAssociatedData, attributes: ChatMessageEntryAttributes) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.controllerInteraction = controllerInteraction
|
self.controllerInteraction = controllerInteraction
|
||||||
self.message = message
|
self.message = message
|
||||||
self.read = read
|
self.read = read
|
||||||
|
self.chatLocation = chatLocation
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.associatedData = associatedData
|
self.associatedData = associatedData
|
||||||
self.attributes = attributes
|
self.attributes = attributes
|
||||||
|
@ -906,7 +906,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||||
|
|
||||||
var needShareButton = false
|
var needShareButton = false
|
||||||
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == item.message.id {
|
||||||
|
needShareButton = false
|
||||||
|
allowFullWidth = true
|
||||||
|
} else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||||
needShareButton = false
|
needShareButton = false
|
||||||
} else if item.message.id.peerId == item.context.account.peerId {
|
} else if item.message.id.peerId == item.context.account.peerId {
|
||||||
if let _ = sourceReference {
|
if let _ = sourceReference {
|
||||||
@ -1134,7 +1137,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
prepareContentPosition = .linear(top: topPosition, bottom: refinedBottomPosition)
|
prepareContentPosition = .linear(top: topPosition, bottom: refinedBottomPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
let contentItem = ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: message, read: read, presentationData: item.presentationData, associatedData: item.associatedData, attributes: attributes)
|
let contentItem = ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: message, read: read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: attributes)
|
||||||
|
|
||||||
var itemSelection: Bool?
|
var itemSelection: Bool?
|
||||||
if case .mosaic = prepareContentPosition {
|
if case .mosaic = prepareContentPosition {
|
||||||
@ -1288,7 +1291,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessageBubble
|
|||||||
}
|
}
|
||||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(item.message.id.peerId), title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubbleContent
|
|||||||
let text: String = item.message.text
|
let text: String = item.message.text
|
||||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(item.message.id.peerId), title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBubbleCont
|
|||||||
}
|
}
|
||||||
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
let mediaAndFlags: (Media, ChatMessageAttachedContentNodeMediaFlags)? = nil
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, true, .peer(item.message.id.peerId), title, nil, text, messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
|
|
||||||
let automaticDownload = shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: selectedFile!)
|
let automaticDownload = shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: selectedFile!)
|
||||||
|
|
||||||
let (initialWidth, refineLayout) = interactiveFileLayout(item.context, item.presentationData, item.message, item.attributes, selectedFile!, automaticDownload, item.message.effectivelyIncoming(item.context.account.peerId), item.associatedData.isRecentActions, item.associatedData.forcedResourceStatus, statusType, CGSize(width: constrainedSize.width - layoutConstants.file.bubbleInsets.left - layoutConstants.file.bubbleInsets.right, height: constrainedSize.height))
|
let (initialWidth, refineLayout) = interactiveFileLayout(item.context, item.presentationData, item.message, item.chatLocation, item.attributes, selectedFile!, automaticDownload, item.message.effectivelyIncoming(item.context.account.peerId), item.associatedData.isRecentActions, item.associatedData.forcedResourceStatus, statusType, CGSize(width: constrainedSize.width - layoutConstants.file.bubbleInsets.left - layoutConstants.file.bubbleInsets.right, height: constrainedSize.height))
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, title, nil, item.message.text.isEmpty ? text : item.message.text, item.message.text.isEmpty ? nil : messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, .peer(item.message.id.peerId), title, nil, item.message.text.isEmpty ? text : item.message.text, item.message.text.isEmpty ? nil : messageEntities, mediaAndFlags, nil, nil, nil, true, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, read: item.read, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, .free, automaticDownload)
|
let (videoLayout, videoApply) = makeVideoLayout(ChatMessageBubbleContentItem(context: item.context, controllerInteraction: item.controllerInteraction, message: item.message, read: item.read, chatLocation: item.chatLocation, presentationData: item.presentationData, associatedData: item.associatedData, attributes: item.content.firstMessageAttributes), params.width - params.leftInset - params.rightInset - avatarInset, displaySize, .free, automaticDownload)
|
||||||
|
|
||||||
let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize)
|
let videoFrame = CGRect(origin: CGPoint(x: (incoming ? (params.leftInset + layoutConstants.bubble.edgeInset + avatarInset + layoutConstants.bubble.contentInsets.left) : (params.width - params.rightInset - videoLayout.contentSize.width - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - deliveryFailedInset)), y: 0.0), size: videoLayout.contentSize)
|
||||||
|
|
||||||
|
@ -204,7 +204,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> Void))) {
|
func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ chatLocation: ChatLocation, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> Void))) {
|
||||||
let currentFile = self.file
|
let currentFile = self.file
|
||||||
|
|
||||||
let titleAsyncLayout = TextNode.asyncLayout(self.titleNode)
|
let titleAsyncLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
@ -214,7 +214,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
|
|
||||||
let currentMessage = self.message
|
let currentMessage = self.message
|
||||||
|
|
||||||
return { context, presentationData, message, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize in
|
return { context, presentationData, message, chatLocation, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize in
|
||||||
return (CGFloat.greatestFiniteMagnitude, { constrainedSize in
|
return (CGFloat.greatestFiniteMagnitude, { constrainedSize in
|
||||||
let titleFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 16.0 / 17.0))
|
let titleFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 16.0 / 17.0))
|
||||||
let descriptionFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0))
|
let descriptionFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0))
|
||||||
@ -300,7 +300,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = chatLocation {
|
||||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
@ -971,12 +971,12 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
self.fetchingCompactTextNode.frame = CGRect(origin: self.descriptionNode.frame.origin, size: fetchingCompactSize)
|
self.fetchingCompactTextNode.frame = CGRect(origin: self.descriptionNode.frame.origin, size: fetchingCompactSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func asyncLayout(_ node: ChatMessageInteractiveFileNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> ChatMessageInteractiveFileNode))) {
|
static func asyncLayout(_ node: ChatMessageInteractiveFileNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ chatLocation: ChatLocation, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> ChatMessageInteractiveFileNode))) {
|
||||||
let currentAsyncLayout = node?.asyncLayout()
|
let currentAsyncLayout = node?.asyncLayout()
|
||||||
|
|
||||||
return { context, presentationData, message, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize in
|
return { context, presentationData, message, chatLocation, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize in
|
||||||
var fileNode: ChatMessageInteractiveFileNode
|
var fileNode: ChatMessageInteractiveFileNode
|
||||||
var fileLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> Void)))
|
var fileLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ message: Message, _ chatLocation: ChatLocation, _ attributes: ChatMessageEntryAttributes, _ file: TelegramMediaFile, _ automaticDownload: Bool, _ incoming: Bool, _ isRecentActions: Bool, _ forcedResourceStatus: FileMediaResourceStatus?, _ dateAndStatusType: ChatMessageDateAndStatusType?, _ constrainedSize: CGSize) -> (CGFloat, (CGSize) -> (CGFloat, (CGFloat) -> (CGSize, (Bool) -> Void)))
|
||||||
|
|
||||||
if let node = node, let currentAsyncLayout = currentAsyncLayout {
|
if let node = node, let currentAsyncLayout = currentAsyncLayout {
|
||||||
fileNode = node
|
fileNode = node
|
||||||
@ -986,7 +986,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
fileLayout = fileNode.asyncLayout()
|
fileLayout = fileNode.asyncLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = fileLayout(context, presentationData, message, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize)
|
let (initialWidth, continueLayout) = fileLayout(context, presentationData, message, chatLocation, attributes, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, constrainedSize)
|
||||||
|
|
||||||
return (initialWidth, { constrainedSize in
|
return (initialWidth, { constrainedSize in
|
||||||
let (finalWidth, finalLayout) = continueLayout(constrainedSize)
|
let (finalWidth, finalLayout) = continueLayout(constrainedSize)
|
||||||
|
@ -257,7 +257,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ final class ChatMessageInvoiceBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, automaticDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, title, subtitle, text, nil, mediaAndFlags, nil, nil, nil, false, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, automaticDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, item.chatLocation, title, subtitle, text, nil, mediaAndFlags, nil, nil, nil, false, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -1030,7 +1030,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? RestrictedContentMessageAttribute {
|
} else if let attribute = attribute as? RestrictedContentMessageAttribute {
|
||||||
rawText = attribute.platformText(platform: "ios", contentSettings: item.context.currentContentSettings.with { $0 }) ?? ""
|
rawText = attribute.platformText(platform: "ios", contentSettings: item.context.currentContentSettings.with { $0 }) ?? ""
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
edited = true
|
edited = true
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
edited = !attribute.isHidden
|
edited = !attribute.isHidden
|
||||||
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
} else if let attribute = attribute as? ViewCountMessageAttribute {
|
||||||
viewCount = attribute.count
|
viewCount = attribute.count
|
||||||
} else if let attribute = attribute as? ReplyThreadMessageAttribute {
|
} else if let attribute = attribute as? ReplyThreadMessageAttribute, case .peer = item.chatLocation {
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .group = channel.info {
|
||||||
dateReplies = Int(attribute.count)
|
dateReplies = Int(attribute.count)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +294,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, title, subtitle, text, entities, mediaAndFlags, badge, actionIcon, actionTitle, true, layoutConstants, constrainedSize)
|
let (initialWidth, continueLayout) = contentNodeLayout(item.presentationData, item.controllerInteraction.automaticMediaDownloadSettings, item.associatedData, item.attributes, item.context, item.controllerInteraction, item.message, item.read, item.chatLocation, title, subtitle, text, entities, mediaAndFlags, badge, actionIcon, actionTitle, true, layoutConstants, constrainedSize)
|
||||||
|
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 8.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||||
|
|
||||||
|
@ -121,6 +121,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
let displaySearchResultsTooltip: (ASDisplayNode, CGRect) -> Void
|
let displaySearchResultsTooltip: (ASDisplayNode, CGRect) -> Void
|
||||||
let openPeersNearby: () -> Void
|
let openPeersNearby: () -> Void
|
||||||
let unarchivePeer: () -> Void
|
let unarchivePeer: () -> Void
|
||||||
|
let scrollToTop: () -> Void
|
||||||
let viewReplies: (MessageId?, ChatReplyThreadMessage) -> Void
|
let viewReplies: (MessageId?, ChatReplyThreadMessage) -> Void
|
||||||
let statuses: ChatPanelInterfaceInteractionStatuses?
|
let statuses: ChatPanelInterfaceInteractionStatuses?
|
||||||
|
|
||||||
@ -196,6 +197,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
openPeersNearby: @escaping () -> Void,
|
openPeersNearby: @escaping () -> Void,
|
||||||
displaySearchResultsTooltip: @escaping (ASDisplayNode, CGRect) -> Void,
|
displaySearchResultsTooltip: @escaping (ASDisplayNode, CGRect) -> Void,
|
||||||
unarchivePeer: @escaping () -> Void,
|
unarchivePeer: @escaping () -> Void,
|
||||||
|
scrollToTop: @escaping () -> Void,
|
||||||
viewReplies: @escaping (MessageId?, ChatReplyThreadMessage) -> Void,
|
viewReplies: @escaping (MessageId?, ChatReplyThreadMessage) -> Void,
|
||||||
statuses: ChatPanelInterfaceInteractionStatuses?
|
statuses: ChatPanelInterfaceInteractionStatuses?
|
||||||
) {
|
) {
|
||||||
@ -270,6 +272,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
self.openPeersNearby = openPeersNearby
|
self.openPeersNearby = openPeersNearby
|
||||||
self.displaySearchResultsTooltip = displaySearchResultsTooltip
|
self.displaySearchResultsTooltip = displaySearchResultsTooltip
|
||||||
self.unarchivePeer = unarchivePeer
|
self.unarchivePeer = unarchivePeer
|
||||||
|
self.scrollToTop = scrollToTop
|
||||||
self.viewReplies = viewReplies
|
self.viewReplies = viewReplies
|
||||||
self.statuses = statuses
|
self.statuses = statuses
|
||||||
}
|
}
|
||||||
|
@ -299,11 +299,12 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
|||||||
@objc func tapped() {
|
@objc func tapped() {
|
||||||
if let interfaceInteraction = self.interfaceInteraction, let message = self.currentMessage {
|
if let interfaceInteraction = self.interfaceInteraction, let message = self.currentMessage {
|
||||||
if self.isReplyThread {
|
if self.isReplyThread {
|
||||||
if let sourceReference = message.sourceReference {
|
interfaceInteraction.scrollToTop()
|
||||||
|
/*if let sourceReference = message.sourceReference {
|
||||||
interfaceInteraction.navigateToMessage(sourceReference.messageId, true)
|
interfaceInteraction.navigateToMessage(sourceReference.messageId, true)
|
||||||
} else {
|
} else {
|
||||||
interfaceInteraction.navigateToMessage(message.id, false)
|
interfaceInteraction.navigateToMessage(message.id, false)
|
||||||
}
|
}*/
|
||||||
} else {
|
} else {
|
||||||
interfaceInteraction.navigateToMessage(message.id, false)
|
interfaceInteraction.navigateToMessage(message.id, false)
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,9 @@ final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, openScheduledMessages: {
|
}, openScheduledMessages: {
|
||||||
}, openPeersNearby: {
|
}, openPeersNearby: {
|
||||||
}, displaySearchResultsTooltip: { _, _ in
|
}, displaySearchResultsTooltip: { _, _ in
|
||||||
}, unarchivePeer: {}, viewReplies: { _, _ in }, statuses: nil)
|
}, unarchivePeer: {
|
||||||
|
}, scrollToTop: {
|
||||||
|
}, viewReplies: { _, _ in }, statuses: nil)
|
||||||
|
|
||||||
self.navigationItem.titleView = self.titleView
|
self.navigationItem.titleView = self.titleView
|
||||||
|
|
||||||
|
@ -190,7 +190,6 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if case .replyThread = interfaceState.chatLocation {
|
if case .replyThread = interfaceState.chatLocation {
|
||||||
self.calendarButton.isHidden = true
|
|
||||||
canSearchMembers = false
|
canSearchMembers = false
|
||||||
}
|
}
|
||||||
self.membersButton.isHidden = (!(interfaceState.search?.query.isEmpty ?? true)) || self.displayActivity || !canSearchMembers
|
self.membersButton.isHidden = (!(interfaceState.search?.query.isEmpty ?? true)) || self.displayActivity || !canSearchMembers
|
||||||
|
@ -92,9 +92,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
|
|||||||
openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId), peekData: nil))
|
openPeer(peerId, .chat(textInputState: nil, subject: .message(messageId), peekData: nil))
|
||||||
case let .replyThreadMessage(replyThreadMessage, messageId):
|
case let .replyThreadMessage(replyThreadMessage, messageId):
|
||||||
if let navigationController = navigationController {
|
if let navigationController = navigationController {
|
||||||
ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in
|
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { c, a in
|
||||||
present(c, a)
|
present(c, a)
|
||||||
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true)
|
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
|
||||||
}
|
}
|
||||||
case let .stickerPack(name):
|
case let .stickerPack(name):
|
||||||
dismissInput()
|
dismissInput()
|
||||||
|
@ -431,7 +431,9 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, openScheduledMessages: {
|
}, openScheduledMessages: {
|
||||||
}, openPeersNearby: {
|
}, openPeersNearby: {
|
||||||
}, displaySearchResultsTooltip: { _, _ in
|
}, displaySearchResultsTooltip: { _, _ in
|
||||||
}, unarchivePeer: {}, viewReplies: { _, _ in }, statuses: nil)
|
}, unarchivePeer: {
|
||||||
|
}, scrollToTop: {
|
||||||
|
}, viewReplies: { _, _ in }, statuses: nil)
|
||||||
|
|
||||||
self.selectionPanel.interfaceInteraction = interfaceInteraction
|
self.selectionPanel.interfaceInteraction = interfaceInteraction
|
||||||
|
|
||||||
|
@ -61,9 +61,9 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
|
|||||||
}
|
}
|
||||||
case let .replyThreadMessage(replyThreadMessage, messageId):
|
case let .replyThreadMessage(replyThreadMessage, messageId):
|
||||||
if let navigationController = controller.navigationController as? NavigationController {
|
if let navigationController = controller.navigationController as? NavigationController {
|
||||||
ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { [weak controller] c, a in
|
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true)
|
}, messageId: replyThreadMessage.messageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
|
||||||
}
|
}
|
||||||
case let .stickerPack(name):
|
case let .stickerPack(name):
|
||||||
let packReference: StickerPackReference = .name(name)
|
let packReference: StickerPackReference = .name(name)
|
||||||
|
@ -321,7 +321,7 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
|
|||||||
return .single(.channelMessage(peerId: peer.id, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)))
|
return .single(.channelMessage(peerId: peer.id, messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)))
|
||||||
case let .replyThread(id, replyId):
|
case let .replyThread(id, replyId):
|
||||||
let replyThreadMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)
|
let replyThreadMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: id)
|
||||||
return fetchChannelReplyThreadMessage(account: account, messageId: replyThreadMessageId)
|
return fetchChannelReplyThreadMessage(account: account, messageId: replyThreadMessageId, atMessageId: nil)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
@ -371,7 +371,7 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
|
|||||||
if let foundPeer = foundPeer {
|
if let foundPeer = foundPeer {
|
||||||
if let threadId = threadId {
|
if let threadId = threadId {
|
||||||
let replyThreadMessageId = MessageId(peerId: foundPeer.id, namespace: Namespaces.Message.Cloud, id: threadId)
|
let replyThreadMessageId = MessageId(peerId: foundPeer.id, namespace: Namespaces.Message.Cloud, id: threadId)
|
||||||
return fetchChannelReplyThreadMessage(account: account, messageId: replyThreadMessageId)
|
return fetchChannelReplyThreadMessage(account: account, messageId: replyThreadMessageId, atMessageId: nil)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
|> `catch` { _ -> Signal<ChatReplyThreadMessage?, NoError> in
|
||||||
return .single(nil)
|
return .single(nil)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user