Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2021-04-13 21:18:44 +04:00
commit a3ba953b24
46 changed files with 4633 additions and 5607 deletions

View File

@ -5740,6 +5740,7 @@ Sorry for the inconvenience.";
"Notification.VoiceChatStarted" = "%1$@ started a voice chat";
"Notification.VoiceChatEnded" = "Voice chat ended (%@)";
"Notification.VoiceChatEndedGroup" = "%1$@ ended the voice chat (%2$@)";
"VoiceChat.Panel.TapToJoin" = "Tap to join";
"VoiceChat.Panel.Members_0" = "%@ participants";
@ -6445,3 +6446,13 @@ Sorry for the inconvenience.";
"VoiceChat.ReminderNotify" = "We will notify you when it starts.";
"Checkout.SuccessfulTooltip" = "You paid %1$@ for %2$@.";
"Privacy.ContactsReset.ContactsDeleted" = "All synced contacts deleted.";
"Privacy.DeleteDrafts.DraftsDeleted" = "All cloud drafts deleted.";
"Privacy.PaymentsClear.PaymentInfoCleared" = "Payment info cleared.";
"Privacy.PaymentsClear.ShippingInfoCleared" = "Shipping info cleared.";
"Privacy.PaymentsClear.AllInfoCleared" = "Payment and shipping info cleared.";

View File

@ -1045,7 +1045,7 @@
CGFloat baselineNudge = (lineHeight - fontLineHeight) * 0.6f;
CGRect rect = *lineFragmentRect;
rect.size.height = lineHeight;
rect.size.height = lineHeight + 2.0f;
CGRect usedRect = *lineFragmentUsedRect;
usedRect.size.height = MAX(lineHeight, usedRect.size.height);

View File

@ -911,7 +911,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
(strongSelf.navigationController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: true, text: messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .window(.root))
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
return .forward(source: id, grouping: .auto, attributes: [])
return .forward(source: id, grouping: .auto, attributes: [], correlationId: nil)
})
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
if let strongSelf = self {

View File

@ -825,7 +825,7 @@ public func createPollController(context: AccountContext, peer: Peer, isQuiz: Bo
dismissImpl?()
completion(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.LocalPoll, id: arc4random64()), publicity: publicity, kind: kind, text: processPollText(state.text), options: options, correctAnswers: correctAnswers, results: TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: resolvedSolution), isClosed: false, deadlineTimeout: deadlineTimeout)), replyToMessageId: nil, localGroupingKey: nil))
completion(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.LocalPoll, id: arc4random64()), publicity: publicity, kind: kind, text: processPollText(state.text), options: options, correctAnswers: correctAnswers, results: TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: resolvedSolution), isClosed: false, deadlineTimeout: deadlineTimeout)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
})
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {

View File

@ -227,7 +227,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: logData)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: logData.count, attributes: [.FileName(fileName: "Log-iOS-Full.txt")])
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}
@ -307,7 +307,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: logData)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: logData.count, attributes: [.FileName(fileName: "Log-iOS-Short.txt")])
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}
@ -379,7 +379,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: logData)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: logData.count, attributes: [.FileName(fileName: "Log-iOS-Full.txt")])
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}
@ -426,7 +426,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
let messages = logs.map { (name, path) -> EnqueueMessage in
let id = arc4random64()
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)])
return .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
}
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
}
@ -457,7 +457,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
let messages = logs.map { (name, path) -> EnqueueMessage in
let id = arc4random64()
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)])
return .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
}
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: messages).start()
}

View File

@ -349,7 +349,7 @@ public final class SecretMediaPreviewController: ViewController {
|> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self, strongSelf.traceVisibility() {
if strongSelf.messageId.peerId.namespace == Namespaces.Peer.CloudUser {
let _ = enqueueMessages(account: strongSelf.context.account, peerId: strongSelf.messageId.peerId, messages: [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil)]).start()
let _ = enqueueMessages(account: strongSelf.context.account, peerId: strongSelf.messageId.peerId, messages: [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]).start()
} else if strongSelf.messageId.peerId.namespace == Namespaces.Peer.SecretChat {
let _ = addSecretChatMessageScreenshot(account: strongSelf.context.account, peerId: strongSelf.messageId.peerId).start()
}

View File

@ -254,7 +254,7 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, String?, [Any]?, String?
}
}
public func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<EnqueueMessage, Void> {
public func legacyEnqueueGifMessage(account: Account, data: Data, correlationId: Int64? = nil) -> Signal<EnqueueMessage, Void> {
return Signal { subscriber in
if let previewImage = UIImage(data: data) {
let dimensions = previewImage.size
@ -286,7 +286,7 @@ public func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<Enqu
fileAttributes.append(.Animated)
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: fileAttributes)
subscriber.putNext(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
subscriber.putNext(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId))
subscriber.putCompletion()
} else {
subscriber.putError(Void())
@ -296,7 +296,7 @@ public func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<Enqu
} |> runOn(Queue.concurrentDefaultQueue())
}
public func legacyEnqueueVideoMessage(account: Account, data: Data) -> Signal<EnqueueMessage, Void> {
public func legacyEnqueueVideoMessage(account: Account, data: Data, correlationId: Int64? = nil) -> Signal<EnqueueMessage, Void> {
return Signal { subscriber in
if let previewImage = UIImage(data: data) {
let dimensions = previewImage.size
@ -328,7 +328,7 @@ public func legacyEnqueueVideoMessage(account: Account, data: Data) -> Signal<En
fileAttributes.append(.Animated)
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: fileAttributes)
subscriber.putNext(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
subscriber.putNext(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId))
subscriber.putCompletion()
} else {
subscriber.putError(Void())
@ -391,7 +391,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
}
var text = caption ?? ""
messages.append(.message(text: text, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId))
messages.append(.message(text: text, attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil))
}
}
case let .asset(asset):
@ -407,7 +407,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
if let timer = item.timer, timer > 0 && timer <= 60 {
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil))
}
messages.append(.message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId))
messages.append(.message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil))
case .tempFile:
break
}
@ -418,13 +418,13 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
arc4random_buf(&randomId, 8)
let resource = LocalFileReferenceMediaResource(localFilePath: path, randomId: randomId)
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: nil, attributes: [.FileName(fileName: name)])
messages.append(.message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId))
messages.append(.message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil))
case let .asset(asset):
var randomId: Int64 = 0
arc4random_buf(&randomId, 8)
let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: arc4random64())
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: nil, attributes: [.FileName(fileName: name)])
messages.append(.message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId))
messages.append(.message(text: caption ?? "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil))
default:
break
}
@ -552,7 +552,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
if let timer = item.timer, timer > 0 && timer <= 60 {
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil))
}
messages.append(.message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId))
messages.append(.message(text: caption ?? "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: item.groupedId, correlationId: nil))
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,11 +6,15 @@ import SwiftSignalKit
import TelegramPresentationData
public func textAlertController(context: AccountContext, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController {
var presentationData = context.sharedContext.currentPresentationData.with { $0 }
return textAlertController(sharedContext: context.sharedContext, forceTheme: forceTheme, title: title, text: text, actions: actions, actionLayout: actionLayout, allowInputInset: allowInputInset, dismissOnOutsideTap: dismissOnOutsideTap)
}
public func textAlertController(sharedContext: SharedAccountContext, forceTheme: PresentationTheme? = nil, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, dismissOnOutsideTap: Bool = true) -> AlertController {
var presentationData = sharedContext.currentPresentationData.with { $0 }
if let forceTheme = forceTheme {
presentationData = presentationData.withUpdated(theme: forceTheme)
}
return textAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: presentationData), themeSignal: context.sharedContext.presentationData |> map {
return textAlertController(alertContext: AlertControllerContext(theme: AlertControllerTheme(presentationData: presentationData), themeSignal: sharedContext.presentationData |> map {
presentationData in
var presentationData = presentationData
if let forceTheme = forceTheme {

View File

@ -9,11 +9,11 @@ import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import PresentationDataUtils
import OverlayStatusController
import AccountContext
import AlertUI
import PresentationDataUtils
import TelegramNotices
import UndoUI
private final class DataPrivacyControllerArguments {
let account: Account
@ -368,7 +368,19 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success))
let text: String?
if info.contains([.paymentInfo, .shippingInfo]) {
text = presentationData.strings.Privacy_PaymentsClear_AllInfoCleared
} else if info.contains(.paymentInfo) {
text = presentationData.strings.Privacy_PaymentsClear_PaymentInfoCleared
} else if info.contains(.shippingInfo) {
text = presentationData.strings.Privacy_PaymentsClear_ShippingInfoCleared
} else {
text = nil
}
if let text = text {
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: text), elevatedLayout: false, action: { _ in return false }))
}
}))
}
dismissAction()
@ -422,7 +434,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success))
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.Privacy_ContactsReset_ContactsDeleted), elevatedLayout: false, action: { _ in return false }))
}))
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]))
}
@ -478,7 +490,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success))
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.Privacy_DeleteDrafts_DraftsDeleted), elevatedLayout: false, action: { _ in return false }))
}))
}
dismissAction()
@ -530,7 +542,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
let controller = ItemListController(context: context, state: signal)
presentControllerImpl = { [weak controller] c in
controller?.present(c, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
controller?.present(c, in: .window(.root))
}
return controller

View File

@ -443,7 +443,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|> take(1)).start(next: { previewTheme, settings in
let saveThemeTemplateFile: (String, LocalFileMediaResource, @escaping () -> Void) -> Void = { title, resource, completion in
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: resource.fileId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/x-tgtheme-ios", size: nil, attributes: [.FileName(fileName: "\(title).tgios-theme")])
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: context.account.peerId, messages: [message]).start()

View File

@ -519,9 +519,9 @@ public final class ShareController: ViewController {
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: url + "\n\n" + text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: url + "\n\n" + text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
} else {
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
@ -529,58 +529,58 @@ public final class ShareController: ViewController {
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .quote(string, url):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .image(representations):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .media(mediaReference):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .mapMedia(media):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .messages(messages):
for peerId in peerIds {
var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty {
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
}
for message in messages {
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto, attributes: []))
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto, attributes: [], correlationId: nil))
}
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
}

View File

@ -403,11 +403,11 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], items: [Prepa
for item in items {
switch item {
case let .text(text):
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
case let .media(media):
switch media {
case let .media(reference):
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: reference, replyToMessageId: nil, localGroupingKey: groupingKey)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: reference, replyToMessageId: nil, localGroupingKey: groupingKey, correlationId: nil)
messages.append(message)
mediaMessages.append(message)

View File

@ -19,30 +19,38 @@ public class OutgoingMessageInfoAttribute: MessageAttribute {
public let uniqueId: Int64
public let flags: OutgoingMessageInfoFlags
public let acknowledged: Bool
public let correlationId: Int64?
public init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool) {
public init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool, correlationId: Int64?) {
self.uniqueId = uniqueId
self.flags = flags
self.acknowledged = acknowledged
self.correlationId = correlationId
}
required public init(decoder: PostboxDecoder) {
self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0)
self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0))
self.acknowledged = decoder.decodeInt32ForKey("ack", orElse: 0) != 0
self.correlationId = decoder.decodeOptionalInt64ForKey("cid")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt64(self.uniqueId, forKey: "u")
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
encoder.encodeInt32(self.acknowledged ? 1 : 0, forKey: "ack")
if let correlationId = self.correlationId {
encoder.encodeInt64(correlationId, forKey: "cid")
} else {
encoder.encodeNil(forKey: "cid")
}
}
public func withUpdatedFlags(_ flags: OutgoingMessageInfoFlags) -> OutgoingMessageInfoAttribute {
return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged)
return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged, correlationId: self.correlationId)
}
public func withUpdatedAcknowledged(_ acknowledged: Bool) -> OutgoingMessageInfoAttribute {
return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged)
return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged, correlationId: self.correlationId)
}
}

View File

@ -249,7 +249,7 @@ func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comm
let name = "\(callId.id)_\(callId.accessHash).log.json"
let path = callLogsPath(account: account) + "/" + name
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)])
let message = EnqueueMessage.message(text: comment, attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message = EnqueueMessage.message(text: comment, attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
return rate
|> then(enqueueMessages(account: account, peerId: peerId, messages: [message])
|> mapToSignal({ _ -> Signal<Void, NoError> in
@ -257,7 +257,7 @@ func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comm
}))
} else if !comment.isEmpty {
return rate
|> then(enqueueMessages(account: account, peerId: peerId, messages: [.message(text: comment, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
|> then(enqueueMessages(account: account, peerId: peerId, messages: [.message(text: comment, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
|> mapToSignal({ _ -> Signal<Void, NoError> in
return .single(Void())
}))

View File

@ -982,7 +982,7 @@ public final class VoiceChatController: ViewController {
dismissController?()
if let strongSelf = self {
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: listenerLink, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: listenerLink, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
|> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self {
strongSelf.presentUndoOverlay(content: .forward(savedMessages: false, text: strongSelf.presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), action: { _ in return true })

View File

@ -67,6 +67,11 @@ public class UnauthorizedAccount {
public var updateLoginTokenEvents: Signal<Void, NoError> {
return self.updateLoginTokenPipe.signal()
}
private let serviceNotificationPipe = ValuePipe<String>()
public var serviceNotificationEvents: Signal<String, NoError> {
return self.serviceNotificationPipe.signal()
}
public var masterDatacenterId: Int32 {
return Int32(self.network.mtProto.datacenterId)
@ -83,8 +88,11 @@ public class UnauthorizedAccount {
self.postbox = postbox
self.network = network
let updateLoginTokenPipe = self.updateLoginTokenPipe
let serviceNotificationPipe = self.serviceNotificationPipe
self.stateManager = UnauthorizedAccountStateManager(network: network, updateLoginToken: {
updateLoginTokenPipe.putNext(Void())
}, displayServiceNotification: { text in
serviceNotificationPipe.putNext(text)
})
network.shouldKeepConnection.set(self.shouldBeServiceTaskMaster.get()

View File

@ -11,13 +11,13 @@ public enum EnqueueMessageGrouping {
}
public enum EnqueueMessage {
case message(text: String, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, replyToMessageId: MessageId?, localGroupingKey: Int64?)
case forward(source: MessageId, grouping: EnqueueMessageGrouping, attributes: [MessageAttribute])
case message(text: String, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, replyToMessageId: MessageId?, localGroupingKey: Int64?, correlationId: Int64?)
case forward(source: MessageId, grouping: EnqueueMessageGrouping, attributes: [MessageAttribute], correlationId: Int64?)
public func withUpdatedReplyToMessageId(_ replyToMessageId: MessageId?) -> EnqueueMessage {
switch self {
case let .message(text, attributes, mediaReference, _, localGroupingKey):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey)
case let .message(text, attributes, mediaReference, _, localGroupingKey, correlationId):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId)
case .forward:
return self
}
@ -25,21 +25,41 @@ public enum EnqueueMessage {
public func withUpdatedAttributes(_ f: ([MessageAttribute]) -> [MessageAttribute]) -> EnqueueMessage {
switch self {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey):
return .message(text: text, attributes: f(attributes), mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey)
case let .forward(source, grouping, attributes):
return .forward(source: source, grouping: grouping, attributes: f(attributes))
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
return .message(text: text, attributes: f(attributes), mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId)
case let .forward(source, grouping, attributes, correlationId):
return .forward(source: source, grouping: grouping, attributes: f(attributes), correlationId: correlationId)
}
}
public func withUpdatedGroupingKey(_ f: (Int64?) -> Int64?) -> EnqueueMessage {
switch self {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: f(localGroupingKey))
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: f(localGroupingKey), correlationId: correlationId)
case .forward:
return self
}
}
public func withUpdatedCorrelationId(_ value: Int64?) -> EnqueueMessage {
switch self {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, _):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: value)
case let .forward(source, grouping, attributes, _):
return .forward(source: source, grouping: grouping, attributes: attributes, correlationId: value)
}
}
}
private extension EnqueueMessage {
var correlationId: Int64? {
switch self {
case let .message(_, _, _, _, _, correlationId):
return correlationId
case let .forward(_, _, _, correlationId):
return correlationId
}
}
}
func augmentMediaWithReference(_ mediaReference: AnyMediaReference) -> Media {
@ -139,7 +159,7 @@ private func opportunisticallyTransformOutgoingMedia(network: Network, postbox:
var hasMedia = false
loop: for message in messages {
switch message {
case let .message(_, _, mediaReference, _, _):
case let .message(_, _, mediaReference, _, _, _):
if mediaReference != nil {
hasMedia = true
break loop
@ -156,14 +176,14 @@ private func opportunisticallyTransformOutgoingMedia(network: Network, postbox:
var signals: [Signal<(Bool, EnqueueMessage), NoError>] = []
for message in messages {
switch message {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey):
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
if let mediaReference = mediaReference {
signals.append(opportunisticallyTransformMessageWithMedia(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, mediaReference: mediaReference, userInteractive: userInteractive)
|> map { result -> (Bool, EnqueueMessage) in
if let result = result {
return (true, .message(text: text, attributes: attributes, mediaReference: .standalone(media: result.media), replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey))
return (true, .message(text: text, attributes: attributes, mediaReference: .standalone(media: result.media), replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId))
} else {
return (false, .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey))
return (false, .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId))
}
})
} else {
@ -235,7 +255,7 @@ public func resendMessages(account: Account, messageIds: [MessageId]) -> Signal<
}
}
messages.append(.message(text: message.text, attributes: filteredAttributes, mediaReference: message.media.first.flatMap(AnyMediaReference.standalone), replyToMessageId: replyToMessageId, localGroupingKey: message.groupingKey))
messages.append(.message(text: message.text, attributes: filteredAttributes, mediaReference: message.media.first.flatMap(AnyMediaReference.standalone), replyToMessageId: replyToMessageId, localGroupingKey: message.groupingKey, correlationId: nil))
}
}
let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: messages.map { (false, $0) })
@ -258,7 +278,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
}
switch message {
case let .message(_, _, _, replyToMessageId, _):
case let .message(_, _, _, replyToMessageId, _, _):
if let replyToMessageId = replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) {
var canBeForwarded = true
if replyMessage.id.namespace != Namespaces.Message.Cloud {
@ -271,10 +291,10 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
}
if canBeForwarded {
updatedMessages.append((true, .forward(source: replyToMessageId, grouping: .none, attributes: [])))
updatedMessages.append((true, .forward(source: replyToMessageId, grouping: .none, attributes: [], correlationId: nil)))
}
}
case let .forward(sourceId, _, _):
case let .forward(sourceId, _, _, _):
if let sourceMessage = forwardedMessageToBeReuploaded(transaction: transaction, id: sourceId) {
var mediaReference: AnyMediaReference?
if sourceMessage.id.peerId.namespace == Namespaces.Peer.SecretChat {
@ -282,7 +302,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
mediaReference = .standalone(media: media)
}
}
updatedMessages.append((transformedMedia, .message(text: sourceMessage.text, attributes: sourceMessage.attributes, mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil)))
updatedMessages.append((transformedMedia, .message(text: sourceMessage.text, attributes: sourceMessage.attributes, mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)))
continue outer
}
}
@ -319,11 +339,11 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
if transformedMedia {
infoFlags.insert(.transformedMedia)
}
attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: infoFlags, acknowledged: false))
attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: infoFlags, acknowledged: false, correlationId: message.correlationId))
globallyUniqueIds.append(randomId)
switch message {
case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey):
case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
var peerAutoremoveTimeout: Int32?
if let peer = peer as? TelegramSecretChat {
var isAction = false
@ -495,7 +515,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
storeMessages.append(StoreMessage(peerId: peerId, namespace: messageNamespace, globallyUniqueId: randomId, groupingKey: localGroupingKey, threadId: threadId, timestamp: effectiveTimestamp, flags: flags, tags: tags, globalTags: globalTags, localTags: localTags, forwardInfo: nil, authorId: authorId, text: text, attributes: attributes, media: mediaList))
case let .forward(source, grouping, requestedAttributes):
case let .forward(source, grouping, requestedAttributes, correlationId):
let sourceMessage = transaction.getMessage(source)
if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] {
if let peer = peer as? TelegramSecretChat {

View File

@ -4,7 +4,7 @@ import SwiftSignalKit
import SyncCore
public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: ChatContextResultCollection, result: ChatContextResult, hideVia: Bool = false, scheduleTime: Int32? = nil) -> EnqueueMessage? {
public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: ChatContextResultCollection, result: ChatContextResult, hideVia: Bool = false, scheduleTime: Int32? = nil, correlationId: Int64? = nil) -> EnqueueMessage? {
var attributes: [MessageAttribute] = []
attributes.append(OutgoingChatContextResultMessageAttribute(queryId: result.queryId, id: result.id, hideVia: hideVia))
if !hideVia {
@ -32,19 +32,19 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
return true
}
if let media: Media = internalReference.file ?? internalReference.image {
return .message(text: caption, attributes: filteredAttributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: filteredAttributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else {
return .message(text: caption, attributes: filteredAttributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: filteredAttributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
}
} else {
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: TelegramMediaGame(gameId: 0, accessHash: 0, name: "", title: internalReference.title ?? "", description: internalReference.description ?? "", image: internalReference.image, file: internalReference.file)), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: TelegramMediaGame(gameId: 0, accessHash: 0, name: "", title: internalReference.title ?? "", description: internalReference.description ?? "", image: internalReference.image, file: internalReference.file)), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
}
} else if let file = internalReference.file, internalReference.type == "gif" {
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else if let image = internalReference.image {
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: image), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: image), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else if let file = internalReference.file {
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else {
return nil
}
@ -56,9 +56,9 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
let thumbnailResource = thumbnail.resource
let imageDimensions = thumbnail.dimensions ?? PixelDimensions(width: 128, height: 128)
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: [TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil)], immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: tmpImage), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: tmpImage), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else {
return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
}
} else if externalReference.type == "document" || externalReference.type == "gif" || externalReference.type == "audio" || externalReference.type == "voice" {
var videoThumbnails: [TelegramMediaFile.VideoThumbnail] = []
@ -118,9 +118,9 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
}
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: videoThumbnails, immediateThumbnailData: nil, mimeType: externalReference.content?.mimeType ?? "application/binary", size: nil, attributes: fileAttributes)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
} else {
return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)
return .message(text: caption, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
}
}
case let .text(text, entities, disableUrlPreview, replyMarkup):
@ -130,21 +130,21 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
if let replyMarkup = replyMarkup {
attributes.append(replyMarkup)
}
return .message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)
return .message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
case let .mapLocation(media, replyMarkup):
if let replyMarkup = replyMarkup {
attributes.append(replyMarkup)
}
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
case let .contact(media, replyMarkup):
if let replyMarkup = replyMarkup {
attributes.append(replyMarkup)
}
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
case let .invoice(media, replyMarkup):
if let replyMarkup = replyMarkup {
attributes.append(replyMarkup)
}
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: correlationId)
}
}

View File

@ -374,7 +374,7 @@ private func uploadedMediaImageContent(network: Network, postbox: Postbox, trans
let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
} else {
updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false))
updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false, correlationId: nil))
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
})
@ -664,7 +664,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
} else {
updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false))
updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: arc4random64(), flags: [.transformedMedia], acknowledged: false, correlationId: nil))
}
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: updatedAttributes, media: currentMessage.media))
})

View File

@ -26,7 +26,7 @@ public func requestStartBot(account: Account, botPeerId: PeerId, payload: String
}
}
} else {
return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]) |> mapToSignal { _ -> Signal<Void, NoError> in
return enqueueMessages(account: account, peerId: botPeerId, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]) |> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
}

View File

@ -17,7 +17,7 @@ public func setSecretChatMessageAutoremoveTimeoutInteractively(account: Account,
transaction.setPeerChatState(peerId, state: updatedState)
}
let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.messageAutoremoveTimeoutUpdated(timeout == nil ? 0 : timeout!))), replyToMessageId: nil, localGroupingKey: nil))])
let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.messageAutoremoveTimeoutUpdated(timeout == nil ? 0 : timeout!))), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))])
}
}
}
@ -32,7 +32,7 @@ public func addSecretChatMessageScreenshot(account: Account, peerId: PeerId) ->
default:
break
}
let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil))])
let _ = enqueueMessages(transaction: transaction, account: account, peerId: peerId, messages: [(true, .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaAction(action: TelegramMediaActionType.historyScreenshot)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))])
}
}
}

View File

@ -54,10 +54,12 @@ final class UnauthorizedAccountStateManager {
private var updateService: UnauthorizedUpdateMessageService?
private let updateServiceDisposable = MetaDisposable()
private let updateLoginToken: () -> Void
private let displayServiceNotification: (String) -> Void
init(network: Network, updateLoginToken: @escaping () -> Void) {
init(network: Network, updateLoginToken: @escaping () -> Void, displayServiceNotification: @escaping (String) -> Void) {
self.network = network
self.updateLoginToken = updateLoginToken
self.displayServiceNotification = displayServiceNotification
}
deinit {
@ -69,11 +71,17 @@ final class UnauthorizedAccountStateManager {
if self.updateService == nil {
self.updateService = UnauthorizedUpdateMessageService()
let updateLoginToken = self.updateLoginToken
let displayServiceNotification = self.displayServiceNotification
self.updateServiceDisposable.set(self.updateService!.pipe.signal().start(next: { updates in
for update in updates {
switch update {
case .updateLoginToken:
updateLoginToken()
case let .updateServiceNotification(flags, _, _, message, _, _):
let popup = (flags & (1 << 0)) != 0
if popup {
displayServiceNotification(message)
}
default:
break
}

View File

@ -4,6 +4,7 @@ import AsyncDisplayKit
import TelegramPresentationData
class AccessoryPanelNode: ASDisplayNode {
var originalFrameBeforeDismissed: CGRect?
var dismiss: (() -> Void)?
var interfaceInteraction: ChatPanelInterfaceInteraction?

View File

@ -1974,7 +1974,7 @@ final class SharedApplicationContext {
if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) {
let _ = applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0)).start()
}
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
return enqueueMessages(account: account, peerId: peerId, messages: [EnqueueMessage.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
|> map { messageIds -> MessageId? in
if messageIds.isEmpty {
return nil

View File

@ -36,6 +36,8 @@ final class UnauthorizedApplicationContext {
let isReady = Promise<Bool>()
var authorizationCompleted: Bool = false
private var serviceNotificationEventsDisposable: Disposable?
init(apiId: Int32, apiHash: String, sharedContext: SharedAccountContextImpl, account: UnauthorizedAccount, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)])) {
self.sharedContext = sharedContext
@ -71,6 +73,20 @@ final class UnauthorizedApplicationContext {
}, { result in
ApplicationSpecificNotice.setPermissionWarning(accountManager: sharedContext.accountManager, permission: .cellularData, value: 0)
})
self.serviceNotificationEventsDisposable = (account.serviceNotificationEvents
|> deliverOnMainQueue).start(next: { [weak self] text in
if let strongSelf = self {
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
let alertController = textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
(strongSelf.rootController.viewControllers.last as? ViewController)?.present(alertController, in: .window(.root))
}
})
}
deinit {
self.serviceNotificationEventsDisposable?.dispose()
}
}

View File

@ -1004,7 +1004,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities))
}
strongSelf.sendMessages([.message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)])
}, sendSticker: { [weak self] fileReference, query, clearInput, sourceNode, sourceRect in
guard let strongSelf = self else {
return false
@ -1043,7 +1043,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
attributes.append(EmojiSearchQueryMessageAttribute(query: query))
}
strongSelf.sendMessages([.message(text: "", attributes: attributes, mediaReference: fileReference.abstract, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: attributes, mediaReference: fileReference.abstract, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)])
return true
}, sendGif: { [weak self] fileReference, sourceNode, sourceRect in
if let strongSelf = self {
@ -1064,7 +1064,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
})
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: fileReference.abstract, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: fileReference.abstract, replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)])
}
return true
}, sendBotContextResultAsGif: { [weak self] collection, result, sourceNode, sourceRect in
@ -1363,7 +1363,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|> deliverOnMainQueue).start(next: { coordinate in
if let strongSelf = self {
if let coordinate = coordinate {
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaMap(latitude: coordinate.latitude, longitude: coordinate.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil)), replyToMessageId: nil, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaMap(latitude: coordinate.latitude, longitude: coordinate.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: nil, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
} else {
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {})]), in: .window(.root))
}
@ -1387,7 +1387,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId)
|> deliverOnMainQueue).start(next: { peer in
if let peer = peer as? TelegramUser, let phone = peer.phone, !phone.isEmpty {
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil)), replyToMessageId: nil, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
}
})
}
@ -1427,7 +1427,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities))
}
strongSelf.sendMessages([.message(text: command, attributes: attributes, mediaReference: nil, replyToMessageId: (postAsReply && messageId != nil) ? messageId! : nil, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: command, attributes: attributes, mediaReference: nil, replyToMessageId: (postAsReply && messageId != nil) ? messageId! : nil, localGroupingKey: nil, correlationId: nil)])
}
}, openInstantPage: { [weak self] message, associatedData in
if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.effectiveNavigationController, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
@ -1712,7 +1712,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ShareMenu_Send, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()
if let strongSelf = self {
strongSelf.sendMessages([.message(text: command, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: command, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
}
}))
}
@ -4074,6 +4074,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.currentPinchController?.addRelativeContentOffset(CGPoint(x: 0.0, y: -offset), transition: transition)
}
}
strongSelf.chatDisplayNode.messageTransitionNode.addExternalOffset(offset: offset, transition: transition, itemNode: itemNode)
}
if case .pinnedMessages = self.presentationInterfaceState.subject {
@ -4480,7 +4482,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else {
isScheduledMessages = false
}
strongSelf.chatDisplayNode.containerLayoutUpdated(validLayout, navigationBarHeight: strongSelf.navigationHeight, transition: .animated(duration: 0.2, curve: .easeInOut), listViewTransaction: { updateSizeAndInsets, _, _, _ in
strongSelf.chatDisplayNode.containerLayoutUpdated(validLayout, navigationBarHeight: strongSelf.navigationHeight, transition: .animated(duration: 0.4, curve: .spring), listViewTransaction: { updateSizeAndInsets, _, _, _ in
var options = transition.options
let _ = options.insert(.Synchronous)
let _ = options.insert(.LowLatency)
@ -4506,9 +4508,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var scrollToItem: ListViewScrollToItem?
if isScheduledMessages, let insertedIndex = insertedIndex {
scrollToItem = ListViewScrollToItem(index: insertedIndex, position: .visible, animated: true, curve: .Default(duration: 0.2), directionHint: .Down)
scrollToItem = ListViewScrollToItem(index: insertedIndex, position: .visible, animated: true, curve: .Spring(duration: 0.4), directionHint: .Down)
} else if transition.historyView.originalView.laterId == nil {
scrollToItem = ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: 0.2), directionHint: .Up)
scrollToItem = ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Spring(duration: 0.4), directionHint: .Up)
}
var stationaryItemRange: (Int, Int)?
@ -4566,12 +4568,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var forwardedMessages: [[EnqueueMessage]] = []
var forwardSourcePeerIds = Set<PeerId>()
for message in transformedMessages {
if case let .forward(source, _, _) = message {
if case let .forward(source, _, _, _) = message {
forwardSourcePeerIds.insert(source.peerId)
var added = false
if var last = forwardedMessages.last {
if let currentMessage = last.first, case let .forward(currentSource, _, _) = currentMessage, currentSource.peerId == source.peerId {
if let currentMessage = last.first, case let .forward(currentSource, _, _, _) = currentMessage, currentSource.peerId == source.peerId {
last.append(message)
added = true
}
@ -5371,7 +5373,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities))
}
strongSelf.sendMessages([.message(text: messageText, attributes: attributes, mediaReference: nil, replyToMessageId: replyMessageId, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: messageText, attributes: attributes, mediaReference: nil, replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)])
}
}
}, sendBotStart: { [weak self] payload in
@ -8308,7 +8310,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
private func editMessageMediaWithMessages(_ messages: [EnqueueMessage]) {
if let message = messages.first, case let .message(text, _, maybeMediaReference, _, _) = message, let mediaReference = maybeMediaReference {
if let message = messages.first, case let .message(text, _, maybeMediaReference, _, _, _) = message, let mediaReference = maybeMediaReference {
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
var state = state
if let editMessageState = state.editMessageState, case let .media(options) = editMessageState.content, !options.isEmpty {
@ -8661,7 +8663,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: fileId), partialReference: nil, resource: ICloudFileResource(urlData: item.urlData, thumbnail: false), previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: mimeType, size: item.fileSize, attributes: attributes)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: replyMessageId, localGroupingKey: groupingKey)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: replyMessageId, localGroupingKey: groupingKey, correlationId: nil)
messages.append(message)
}
if let _ = groupingKey, messages.count % 10 == 0 {
@ -8899,7 +8901,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, {
@ -8954,7 +8956,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
})
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
enqueueMessages.append(message)
}
}
@ -9013,7 +9015,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
})
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
strongSelf.sendMessages([message])
} else {
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in
@ -9031,7 +9033,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
})
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)
strongSelf.sendMessages([message])
}
}), completed: nil, cancelled: nil)
@ -9406,7 +9408,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let value = value {
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: canSendMessagesToChat(self.presentationInterfaceState) ? self.presentationData.strings.Conversation_SendDice : nil), elevatedLayout: false, action: { [weak self] action in
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState), action == .undo {
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)])
}
return false
}), in: .current)
@ -9427,9 +9429,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let defaultReplyMessageId = defaultReplyMessageId {
switch message {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey):
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
if replyToMessageId == nil {
message = .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: defaultReplyMessageId, localGroupingKey: localGroupingKey)
message = .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: defaultReplyMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId)
}
case .forward:
break
@ -9598,7 +9600,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
fileAttributes.append(.ImageSize(size: PixelDimensions(size)))
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "image/webp", size: data.count, attributes: fileAttributes)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
@ -9814,7 +9816,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
})
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: data.compressedData.count, attributes: [.Audio(isVoice: true, duration: Int(data.duration), title: nil, performer: nil, waveform: waveformBuffer)])), replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)])
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: data.compressedData.count, attributes: [.Audio(isVoice: true, duration: Int(data.duration), title: nil, performer: nil, waveform: waveformBuffer)])), replyToMessageId: strongSelf.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)])
strongSelf.recorderFeedback?.tap()
strongSelf.recorderFeedback = nil
@ -9910,7 +9912,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
})
let messages: [EnqueueMessage] = [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: recordedMediaPreview.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int(recordedMediaPreview.fileSize), attributes: [.Audio(isVoice: true, duration: Int(recordedMediaPreview.duration), title: nil, performer: nil, waveform: waveformBuffer)])), replyToMessageId: self.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil)]
let messages: [EnqueueMessage] = [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: recordedMediaPreview.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int(recordedMediaPreview.fileSize), attributes: [.Audio(isVoice: true, duration: Int(recordedMediaPreview.duration), title: nil, performer: nil, waveform: waveformBuffer)])), replyToMessageId: self.presentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil)]
let transformedMessages: [EnqueueMessage]
if let silentPosting = silentPosting {
@ -10628,7 +10630,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}), in: .current)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messages.map { message -> EnqueueMessage in
return .forward(source: message.id, grouping: .auto, attributes: [])
return .forward(source: message.id, grouping: .auto, attributes: [], correlationId: nil)
})
|> deliverOnMainQueue).start(next: { messageIds in
if let strongSelf = self {
@ -10986,7 +10988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
Queue.mainQueue().async {
unblockingPeer.set(false)
if let strongSelf = self, restartBot {
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]).start()
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]).start()
}
}
})).start())

View File

@ -393,6 +393,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var expandedInputDimNode: ASDisplayNode?
private var dropDimNode: ASDisplayNode?
let messageTransitionNode: ChatMessageTransitionNode
private var containerLayoutAndNavigationBarHeight: (ContainerViewLayout, CGFloat)?
@ -501,6 +503,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.navigationBarSeparatorNode = ASDisplayNode()
self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor
self.messageTransitionNode = ChatMessageTransitionNode(listNode: self.historyNode)
super.init()
@ -593,6 +597,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.addSubnode(self.navigationBarBackroundNode)
self.addSubnode(self.navigationBarSeparatorNode)
self.addSubnode(self.messageTransitionNode)
if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding {
self.navigationBarBackroundNode.isHidden = true
self.navigationBarSeparatorNode.isHidden = true
@ -1150,7 +1157,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var dismissedInputPanelNode: ASDisplayNode?
var dismissedSecondaryInputPanelNode: ASDisplayNode?
var dismissedAccessoryPanelNode: ASDisplayNode?
var dismissedAccessoryPanelNode: AccessoryPanelNode?
var dismissedInputContextPanelNode: ChatInputContextPanelNode?
var dismissedOverlayContextPanelNode: ChatInputContextPanelNode?
@ -1743,6 +1750,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let inputPanelFrame = inputPanelFrame {
transitionTargetY = inputPanelFrame.minY
}
dismissedAccessoryPanelNode.originalFrameBeforeDismissed = dismissedAccessoryPanelNode.frame
transition.updateFrame(node: dismissedAccessoryPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: transitionTargetY), size: dismissedAccessoryPanelNode.frame.size), completion: { _ in
frameCompleted = true
completed()
@ -2607,7 +2617,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines)
let peerId = effectivePresentationInterfaceState.chatLocation.peerId
if peerId.namespace != Namespaces.Peer.SecretChat, let interactiveEmojis = self.interactiveEmojis, interactiveEmojis.emojis.contains(trimmedInputText) {
messages.append(.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil))
messages.append(.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: trimmedInputText)), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil))
} else {
let inputText = convertMarkdownToAttributes(effectiveInputText)
@ -2624,7 +2634,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else {
webpage = self.chatPresentationInterfaceState.urlPreview?.1
}
messages.append(.message(text: text.string, attributes: attributes, mediaReference: webpage.flatMap(AnyMediaReference.standalone), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil))
messages.append(.message(text: text.string, attributes: attributes, mediaReference: webpage.flatMap(AnyMediaReference.standalone), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil))
}
}
@ -2654,7 +2664,22 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
for id in forwardMessageIds {
messages.append(.forward(source: id, grouping: .auto, attributes: []))
messages.append(.forward(source: id, grouping: .auto, attributes: [], correlationId: nil))
}
}
if !messages.isEmpty, case .message = messages[messages.count - 1] {
let correlationId = Int64.random(in: 0 ..< Int64.max)
messages[messages.count - 1] = messages[messages.count - 1].withUpdatedCorrelationId(correlationId)
var replyPanel: ReplyAccessoryPanelNode?
if let accessoryPanelNode = self.accessoryPanelNode as? ReplyAccessoryPanelNode {
replyPanel = accessoryPanelNode
}
if let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode, let textInput = inputPanelNode.makeSnapshotForTransition() {
let source: ChatMessageTransitionNode.Source = .textInput(textInput: textInput, replyPanel: replyPanel)
self.messageTransitionNode.add(correlationId: correlationId, source: source, initiated: {
})
}
}

View File

@ -1780,7 +1780,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if let historyView = strongSelf.historyView {
if historyView.filteredEntries.isEmpty {
if let firstEntry = historyView.originalView.entries.first {
var isPeerJoined = false
var emptyType = ChatHistoryNodeLoadState.EmptyType.generic
for media in firstEntry.message.media {
if let action = media as? TelegramMediaAction {
@ -1893,6 +1892,28 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} else if transition.scrolledToSomeIndex {
self?.scrolledToSomeIndex?()
}
if let currentSendAnimationCorrelationId = strongSelf.currentSendAnimationCorrelationId {
var foundItemNode: ChatMessageItemView?
strongSelf.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item {
for (message, _) in item.content {
for attribute in message.attributes {
if let attribute = attribute as? OutgoingMessageInfoAttribute {
if attribute.correlationId == currentSendAnimationCorrelationId {
foundItemNode = itemNode
}
}
}
}
}
}
if let foundItemNode = foundItemNode {
strongSelf.currentSendAnimationCorrelationId = nil
strongSelf.animationCorrelationMessageFound?(foundItemNode, currentSendAnimationCorrelationId)
}
}
strongSelf.hasActiveTransition = false
strongSelf.dequeueHistoryViewTransitions()
@ -2245,4 +2266,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
})
self.selectionScrollDisplayLink?.isPaused = false
}
private var currentSendAnimationCorrelationId: Int64?
func setCurrentSendAnimationCorrelationId(_ value: Int64?) {
self.currentSendAnimationCorrelationId = value
}
var animationCorrelationMessageFound: ((ChatMessageItemView, Int64?) -> Void)?
}

View File

@ -475,7 +475,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
let id = arc4random64()
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: logPath, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: "CallStats.log")])
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}

View File

@ -233,6 +233,23 @@ class ChatMessageBackground: ASDisplayNode {
self.imageNode.image = image
self.outlineImageNode.image = outlineImage
}
func animateFrom(sourceView: UIView, transition: ContainedViewLayoutTransition) {
if transition.isAnimated {
self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.outlineImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.view.addSubview(sourceView)
sourceView.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: sourceView.bounds.size)
sourceView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceView] _ in
sourceView?.removeFromSuperview()
})
transition.animateFrame(node: self.imageNode, from: sourceView.frame)
transition.animateFrame(node: self.outlineImageNode, from: sourceView.frame)
transition.updateFrame(view: sourceView, frame: CGRect(origin: self.imageNode.frame.origin, size: CGSize(width: self.imageNode.frame.width - 7.0, height: self.imageNode.frame.height)))
}
}
}
final class ChatMessageShadowNode: ASDisplayNode {

View File

@ -362,7 +362,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
}
private let mainContextSourceNode: ContextExtractedContentContainingNode
let mainContextSourceNode: ContextExtractedContentContainingNode
private let mainContainerNode: ContextControllerSourceNode
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
private let backgroundNode: ChatMessageBackground
@ -553,6 +553,40 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func cancelInsertionAnimations() {
self.shadowNode.layer.removeAllAnimations()
func process(node: ASDisplayNode) {
if node === self.accessoryItemNode {
return
}
if node !== self {
switch node {
case let node as ContextExtractedContentContainingNode:
process(node: node.contentNode)
return
case _ as ContextControllerSourceNode, _ as ContextExtractedContentNode:
break
default:
node.layer.removeAllAnimations()
node.layer.allowsGroupOpacity = false
return
}
}
guard let subnodes = node.subnodes else {
return
}
for subnode in subnodes {
process(node: subnode)
}
}
process(node: self)
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
super.animateInsertion(currentTimestamp, duration: duration, short: short)
@ -614,6 +648,27 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
}
}
func animateContentFromTextInputField(textInput: ChatMessageTransitionNode.Source.TextInput, transition: ContainedViewLayoutTransition) {
let widthDifference = self.backgroundNode.frame.width - textInput.backgroundView.frame.width
self.backgroundNode.animateFrom(sourceView: textInput.backgroundView, transition: transition)
for contentNode in self.contentNodes {
if let contentNode = contentNode as? ChatMessageTextBubbleContentNode {
let localSourceContentFrame = self.mainContextSourceNode.contentNode.view.convert(textInput.contentView.frame.offsetBy(dx: self.mainContextSourceNode.contentRect.minX, dy: self.mainContextSourceNode.contentRect.minY), to: contentNode.view)
textInput.contentView.frame = localSourceContentFrame
contentNode.animateFrom(sourceView: textInput.contentView, widthDifference: widthDifference, transition: transition)
}
}
}
func animateReplyPanel(sourceReplyPanel: ChatMessageTransitionNode.ReplyPanel, transition: ContainedViewLayoutTransition) {
if let replyInfoNode = self.replyInfoNode {
let localRect = self.mainContextSourceNode.contentNode.view.convert(sourceReplyPanel.relativeSourceRect, to: replyInfoNode.view)
replyInfoNode.animateFromInputPanel(sourceReplyPanel: sourceReplyPanel, localRect: localRect, transition: transition)
}
}
override func didLoad() {
super.didLoad()

View File

@ -729,6 +729,9 @@ public class ChatMessageItemView: ListViewItemNode {
avatarNode.frame = CGRect(origin: CGPoint(x: leftInset + 3.0, y: self.apparentFrame.height - 38.0 - self.insets.top - 2.0 - UIScreenPixel), size: CGSize(width: 38.0, height: 38.0))
}
}
func cancelInsertionAnimations() {
}
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
if short {

View File

@ -229,4 +229,84 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
})
}
}
func animateFromInputPanel(sourceReplyPanel: ChatMessageTransitionNode.ReplyPanel, localRect: CGRect, transition: ContainedViewLayoutTransition) {
if let titleNode = self.titleNode {
let offset = CGPoint(
x: localRect.minX + sourceReplyPanel.titleNode.frame.minX - titleNode.frame.minX,
y: localRect.minY + sourceReplyPanel.titleNode.frame.midY - titleNode.frame.midY
)
transition.animatePositionAdditive(node: titleNode, offset: offset)
self.addSubnode(sourceReplyPanel.titleNode)
titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
sourceReplyPanel.titleNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceReplyPanel] _ in
sourceReplyPanel?.titleNode.removeFromSupernode()
})
sourceReplyPanel.titleNode.frame = sourceReplyPanel.titleNode.frame.offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y)
transition.animatePositionAdditive(node: sourceReplyPanel.titleNode, offset: CGPoint(x: offset.x, y: offset.y), removeOnCompletion: false)
}
if let textNode = self.textNode {
let offset = CGPoint(
x: localRect.minX + sourceReplyPanel.textNode.frame.minX - textNode.frame.minX,
y: localRect.minY + sourceReplyPanel.textNode.frame.midY - textNode.frame.midY
)
transition.animatePositionAdditive(node: textNode, offset: offset)
self.addSubnode(sourceReplyPanel.textNode)
textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
sourceReplyPanel.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceReplyPanel] _ in
sourceReplyPanel?.textNode.removeFromSupernode()
})
sourceReplyPanel.textNode.frame = sourceReplyPanel.textNode.frame.offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y)
transition.animatePositionAdditive(node: sourceReplyPanel.textNode, offset: CGPoint(x: offset.x, y: offset.y), removeOnCompletion: false)
}
if let imageNode = self.imageNode {
let offset = CGPoint(
x: localRect.minX + sourceReplyPanel.imageNode.frame.midX - imageNode.frame.midX,
y: localRect.minY + sourceReplyPanel.imageNode.frame.midY - imageNode.frame.midY
)
transition.animatePositionAdditive(node: imageNode, offset: offset)
self.addSubnode(sourceReplyPanel.imageNode)
imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
sourceReplyPanel.imageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceReplyPanel] _ in
sourceReplyPanel?.imageNode.removeFromSupernode()
})
sourceReplyPanel.imageNode.frame = sourceReplyPanel.imageNode.frame.offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y)
transition.animatePositionAdditive(node: sourceReplyPanel.imageNode, offset: CGPoint(x: offset.x, y: offset.y), removeOnCompletion: false)
}
do {
let lineNode = self.lineNode
let offset = CGPoint(
x: localRect.minX + sourceReplyPanel.lineNode.frame.minX - lineNode.frame.minX,
y: localRect.minY + sourceReplyPanel.lineNode.frame.minY - lineNode.frame.minY
)
transition.animatePositionAdditive(node: lineNode, offset: offset)
self.addSubnode(sourceReplyPanel.lineNode)
lineNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
sourceReplyPanel.lineNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceReplyPanel] _ in
sourceReplyPanel?.lineNode.removeFromSupernode()
})
sourceReplyPanel.lineNode.frame = sourceReplyPanel.lineNode.frame.offsetBy(dx: localRect.minX - offset.x, dy: localRect.minY - offset.y)
transition.animatePositionAdditive(node: sourceReplyPanel.lineNode, offset: CGPoint(x: offset.x, y: offset.y), removeOnCompletion: false)
}
}
}

View File

@ -640,4 +640,24 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
override func getStatusNode() -> ASDisplayNode? {
return self.statusNode
}
func animateFrom(sourceView: UIView, widthDifference: CGFloat, transition: ContainedViewLayoutTransition) {
self.view.addSubview(sourceView)
sourceView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak sourceView] _ in
sourceView?.removeFromSuperview()
})
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
let offset = CGPoint(
x: sourceView.frame.minX - (self.textNode.frame.minX - 0.0),
y: sourceView.frame.minY - (self.textNode.frame.minY - 3.0)
)
transition.animatePositionAdditive(node: self.textNode, offset: offset)
transition.updatePosition(layer: sourceView.layer, position: CGPoint(x: sourceView.layer.position.x - offset.x, y: sourceView.layer.position.y - offset.y))
self.statusNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
transition.animatePositionAdditive(node: self.statusNode, offset: CGPoint(x: -widthDifference, y: 0.0))
}
}

View File

@ -0,0 +1,191 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import ContextUI
final class ChatMessageTransitionNode: ASDisplayNode {
final class ReplyPanel {
let titleNode: ASDisplayNode
let textNode: ASDisplayNode
let lineNode: ASDisplayNode
let imageNode: ASDisplayNode
let relativeSourceRect: CGRect
init(titleNode: ASDisplayNode, textNode: ASDisplayNode, lineNode: ASDisplayNode, imageNode: ASDisplayNode, relativeSourceRect: CGRect) {
self.titleNode = titleNode
self.textNode = textNode
self.lineNode = lineNode
self.imageNode = imageNode
self.relativeSourceRect = relativeSourceRect
}
}
enum Source {
final class TextInput {
let backgroundView: UIView
let contentView: UIView
let sourceRect: CGRect
init(backgroundView: UIView, contentView: UIView, sourceRect: CGRect) {
self.backgroundView = backgroundView
self.contentView = contentView
self.sourceRect = sourceRect
}
}
case textInput(textInput: TextInput, replyPanel: ReplyAccessoryPanelNode?)
}
private final class AnimatingItemNode: ASDisplayNode {
private let itemNode: ChatMessageItemView
private let contextSourceNode: ContextExtractedContentContainingNode
private let source: ChatMessageTransitionNode.Source
private let scrollingContainer: ASDisplayNode
private let containerNode: ASDisplayNode
var animationEnded: (() -> Void)?
init(itemNode: ChatMessageItemView, contextSourceNode: ContextExtractedContentContainingNode, source: ChatMessageTransitionNode.Source) {
self.itemNode = itemNode
self.scrollingContainer = ASDisplayNode()
self.containerNode = ASDisplayNode()
self.contextSourceNode = contextSourceNode
self.source = source
super.init()
self.addSubnode(self.scrollingContainer)
self.scrollingContainer.addSubnode(self.containerNode)
}
deinit {
self.contextSourceNode.addSubnode(self.contextSourceNode.contentNode)
}
func beginAnimation() {
switch self.source {
case let .textInput(textInput, replyPanel):
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: nil)
let sourceAbsoluteRect = textInput.backgroundView.frame.offsetBy(dx: textInput.sourceRect.minX, dy: textInput.sourceRect.minY)
var sourceReplyPanel: ReplyPanel?
if let replyPanel = replyPanel, let replyPanelParentView = replyPanel.view.superview {
var replySourceAbsoluteFrame = replyPanelParentView.convert(replyPanel.originalFrameBeforeDismissed ?? replyPanel.frame, to: nil)
replySourceAbsoluteFrame.origin.x -= sourceAbsoluteRect.minX - self.contextSourceNode.contentRect.minX
replySourceAbsoluteFrame.origin.y -= sourceAbsoluteRect.minY - self.contextSourceNode.contentRect.minY
sourceReplyPanel = ReplyPanel(titleNode: replyPanel.titleNode, textNode: replyPanel.textNode, lineNode: replyPanel.lineNode, imageNode: replyPanel.imageNode, relativeSourceRect: replySourceAbsoluteFrame)
}
self.itemNode.cancelInsertionAnimations()
let duration: Double = 0.4
let delay: Double = 0.0
let transition: ContainedViewLayoutTransition = .animated(duration: duration * 0.8, curve: .spring)
if let itemNode = self.itemNode as? ChatMessageBubbleItemNode {
itemNode.animateContentFromTextInputField(textInput: textInput, transition: transition)
if let sourceReplyPanel = sourceReplyPanel {
itemNode.animateReplyPanel(sourceReplyPanel: sourceReplyPanel, transition: transition)
}
}
self.containerNode.frame = targetAbsoluteRect.offsetBy(dx: -self.contextSourceNode.contentRect.minX, dy: self.contextSourceNode.contentRect.minY)
self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: sourceAbsoluteRect.minY - targetAbsoluteRect.minY), to: CGPoint(), duration: duration, delay: delay, timingFunction: kCAMediaTimingFunctionSpring, additive: true, force: true, completion: { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.endAnimation()
})
self.containerNode.layer.animatePosition(from: CGPoint(x: sourceAbsoluteRect.minX - targetAbsoluteRect.minX, y: 0.0), to: CGPoint(), duration: duration * 0.8, delay: delay, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
}
private func endAnimation() {
self.animationEnded?()
}
func addExternalOffset(offset: CGFloat, transition: ContainedViewLayoutTransition, itemNode: ListViewItemNode?) {
var applyOffset = false
if let itemNode = itemNode {
if itemNode === self.itemNode {
applyOffset = true
}
} else {
applyOffset = true
}
if applyOffset {
self.scrollingContainer.bounds = self.scrollingContainer.bounds.offsetBy(dx: 0.0, dy: -offset)
transition.animateOffsetAdditive(node: self.scrollingContainer, offset: offset)
}
}
}
private let listNode: ChatHistoryListNode
private var currentPendingItem: (Int64, Source, () -> Void)?
private var animatingItemNodes: [AnimatingItemNode] = []
init(listNode: ChatHistoryListNode) {
self.listNode = listNode
super.init()
self.listNode.animationCorrelationMessageFound = { [weak self] itemNode, correlationId in
guard let strongSelf = self, let (currentId, currentSource, initiated) = strongSelf.currentPendingItem else {
return
}
if currentId == correlationId {
strongSelf.currentPendingItem = nil
strongSelf.beginAnimation(itemNode: itemNode, source: currentSource)
initiated()
}
}
}
func add(correlationId: Int64, source: Source, initiated: @escaping () -> Void) {
self.currentPendingItem = (correlationId, source, initiated)
self.listNode.setCurrentSendAnimationCorrelationId(correlationId)
}
private func beginAnimation(itemNode: ChatMessageItemView, source: Source) {
if let itemNode = itemNode as? ChatMessageBubbleItemNode {
let animatingItemNode = AnimatingItemNode(itemNode: itemNode, contextSourceNode: itemNode.mainContextSourceNode, source: source)
self.animatingItemNodes.append(animatingItemNode)
self.addSubnode(animatingItemNode)
animatingItemNode.animationEnded = { [weak self, weak animatingItemNode] in
guard let strongSelf = self, let animatingItemNode = animatingItemNode else {
return
}
animatingItemNode.removeFromSupernode()
if let index = strongSelf.animatingItemNodes.firstIndex(where: { $0 === animatingItemNode }) {
strongSelf.animatingItemNodes.remove(at: index)
}
}
animatingItemNode.frame = self.bounds
animatingItemNode.beginAnimation()
} else if let itemNode = itemNode as? ChatMessageStickerItemNode {
} else if let itemNode = itemNode as? ChatMessageAnimatedStickerItemNode {
}
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
return nil
}
func addExternalOffset(offset: CGFloat, transition: ContainedViewLayoutTransition, itemNode: ListViewItemNode?) {
for animatingItemNode in self.animatingItemNodes {
animatingItemNode.addExternalOffset(offset: offset, transition: transition, itemNode: itemNode)
}
}
}

View File

@ -162,20 +162,30 @@ private func calclulateTextFieldMinHeight(_ presentationInterfaceState: ChatPres
}
private var currentTextInputBackgroundImage: (UIColor, UIColor, CGFloat, UIImage)?
private func textInputBackgroundImage(backgroundColor: UIColor, strokeColor: UIColor, diameter: CGFloat) -> UIImage? {
if let current = currentTextInputBackgroundImage {
private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat) -> UIImage? {
if let backgroundColor = backgroundColor, let current = currentTextInputBackgroundImage {
if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) {
return current.3
}
}
let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setBlendMode(.clear)
context.setFillColor(UIColor.clear.cgColor)
if let backgroundColor = backgroundColor {
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
} else {
context.clear(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
}
if let inputBackgroundColor = inputBackgroundColor {
context.setBlendMode(.normal)
context.setFillColor(inputBackgroundColor.cgColor)
} else {
context.setBlendMode(.clear)
context.setFillColor(UIColor.clear.cgColor)
}
context.fillEllipse(in: CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setBlendMode(.normal)
context.setStrokeColor(strokeColor.cgColor)
let strokeWidth: CGFloat = 1.0
@ -183,7 +193,9 @@ private func textInputBackgroundImage(backgroundColor: UIColor, strokeColor: UIC
context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: diameter - strokeWidth, height: diameter - strokeWidth))
})?.stretchableImage(withLeftCapWidth: Int(diameter) / 2, topCapHeight: Int(diameter) / 2)
if let image = image {
currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, image)
if let backgroundColor = backgroundColor {
currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, image)
}
return image
} else {
return nil
@ -205,6 +217,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var textInputNode: EditableTextNode?
let textInputBackgroundNode: ASImageNode
private var transparentTextInputBackgroundImage: UIImage?
let actionButtons: ChatTextInputActionButtonsNode
var mediaRecordingAccessibilityArea: AccessibilityAreaNode?
private let counterTextNode: ImmediateTextNode
@ -636,7 +649,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let maxNumberOfLines = min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22)
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * 22.0 + 10.0)
let updatedMaxHeight = (CGFloat(maxNumberOfLines) * (22.0 + 2.0) + 10.0)
textFieldHeight = max(textFieldMinHeight, min(updatedMaxHeight, unboundTextFieldHeight))
} else {
@ -779,7 +792,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
backgroundColor = interfaceState.theme.chat.inputPanel.panelBackgroundColor
}
self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight)
self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight)
self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight)
self.searchLayoutClearImageNode.image = PresentationResourcesChat.chatInputTextFieldClearImage(interfaceState.theme)
@ -2152,5 +2166,28 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
}
return nil
}
func makeSnapshotForTransition() -> ChatMessageTransitionNode.Source.TextInput? {
guard let backgroundImage = self.transparentTextInputBackgroundImage else {
return nil
}
guard let textInputNode = self.textInputNode else {
return nil
}
let backgroundView = UIImageView(image: backgroundImage)
backgroundView.frame = self.textInputBackgroundNode.frame
guard let contentView = textInputNode.view.snapshotView(afterScreenUpdates: false) else {
return nil
}
contentView.frame = textInputNode.frame
return ChatMessageTransitionNode.Source.TextInput(
backgroundView: backgroundView,
contentView: contentView,
sourceRect: self.view.convert(self.bounds, to: nil)
)
}
}

View File

@ -198,7 +198,7 @@ func legacyInstantVideoController(theme: PresentationTheme, panelFrame: CGRect,
}
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: arc4random64()), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: [.FileName(fileName: "video.mp4"), .Video(duration: Int(finalDuration), size: PixelDimensions(finalDimensions), flags: [.instantRoundVideo])])
var message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
var message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let scheduleTime: Int32? = scheduleTimestamp > 0 ? scheduleTimestamp : nil

View File

@ -67,7 +67,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
params.dismissInput()
let controllerParams = LocationViewParams(sendLiveLocation: { location in
let outMessage: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: nil, localGroupingKey: nil)
let outMessage: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
params.enqueueMessage(outMessage)
}, stopLiveLocation: { messageId in
params.context.liveLocationManager?.cancelLiveLocation(peerId: messageId?.peerId ?? params.message.id.peerId)

View File

@ -4273,7 +4273,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
if let peer = peer as? TelegramUser, let _ = peer.botInfo {
strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: block).start())
if !block {
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]).start()
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: "/start", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]).start()
if let navigationController = strongSelf.controller?.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id)))
}
@ -4643,7 +4643,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
case .help:
text = "/help"
}
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]).start()
let _ = enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: [.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)]).start()
if let navigationController = strongSelf.controller?.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId)))
@ -5629,7 +5629,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in
return .forward(source: id, grouping: .auto, attributes: [])
return .forward(source: id, grouping: .auto, attributes: [], correlationId: nil)
})
|> deliverOnMainQueue).start(next: { [weak self] messageIds in
if let strongSelf = self {

View File

@ -48,10 +48,12 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1
self.titleNode.displaysAsynchronously = false
self.titleNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
self.textNode = ImmediateTextNode()
self.textNode.maximumNumberOfLines = 1
self.textNode.displaysAsynchronously = false
self.textNode.insets = UIEdgeInsets(top: 3.0, left: 0.0, bottom: 3.0, right: 0.0)
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = [.subsequentUpdates]
@ -162,8 +164,8 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
isMedia = false
}
strongSelf.titleNode.attributedText = NSAttributedString(string: authorName, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: isMedia ? strongSelf.theme.chat.inputPanel.secondaryTextColor : strongSelf.theme.chat.inputPanel.primaryTextColor)
strongSelf.titleNode.attributedText = NSAttributedString(string: authorName, font: Font.medium(14.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor)
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: isMedia ? strongSelf.theme.chat.inputPanel.secondaryTextColor : strongSelf.theme.chat.inputPanel.primaryTextColor)
let headerString: String
if let message = message, message.flags.contains(.Incoming), let author = message.author {
@ -239,20 +241,28 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.closeButton.frame = closeButtonFrame
self.actionArea.frame = CGRect(origin: CGPoint(x: leftInset, y: 2.0), size: CGSize(width: closeButtonFrame.minX - leftInset, height: bounds.height))
self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0))
if self.lineNode.supernode == self {
self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0))
}
var imageTextInset: CGFloat = 0.0
if !self.imageNode.isHidden {
imageTextInset = 9.0 + 35.0
}
self.imageNode.frame = CGRect(origin: CGPoint(x: leftInset + 9.0, y: 8.0), size: CGSize(width: 35.0, height: 35.0))
if self.imageNode.supernode == self {
self.imageNode.frame = CGRect(origin: CGPoint(x: leftInset + 9.0, y: 8.0), size: CGSize(width: 35.0, height: 35.0))
}
let titleSize = self.titleNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 7.0), size: titleSize)
if self.titleNode.supernode == self {
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset - self.titleNode.insets.left, y: 7.0 - self.titleNode.insets.top), size: titleSize)
}
let textSize = self.textNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height))
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 25.0), size: textSize)
if self.textNode.supernode == self {
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset - self.textNode.insets.left, y: 25.0 - self.textNode.insets.top), size: textSize)
}
}
@objc func closePressed() {

View File

@ -1121,7 +1121,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
if !found {
let controllerParams = LocationViewParams(sendLiveLocation: { location in
let outMessage: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: nil, localGroupingKey: nil)
let outMessage: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: location), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
// params.enqueueMessage(outMessage)
}, stopLiveLocation: { messageId in
if let messageId = messageId {

@ -1 +1 @@
Subproject commit 064de810ce35411d8e18f0a10e2ed6fc2a3373a5
Subproject commit cff573909eb35be75491b6967063b94d81ad0828

View File

@ -200,17 +200,17 @@ final class WatchSendMessageHandler: WatchRequestHandler {
if args.replyToMid != 0, let peerId = peerId {
replyMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: args.replyToMid)
}
messageSignal = .single((.message(text: args.text, attributes: [], mediaReference: nil, replyToMessageId: replyMessageId, localGroupingKey: nil), peerId))
messageSignal = .single((.message(text: args.text, attributes: [], mediaReference: nil, replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil), peerId))
} else if let args = subscription as? TGBridgeSendLocationMessageSubscription, let location = args.location {
let peerId = makePeerIdFromBridgeIdentifier(args.peerId)
let map = TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: makeVenue(from: location.venue), liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil)
messageSignal = .single((.message(text: "", attributes: [], mediaReference: .standalone(media: map), replyToMessageId: nil, localGroupingKey: nil), peerId))
messageSignal = .single((.message(text: "", attributes: [], mediaReference: .standalone(media: map), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil), peerId))
} else if let args = subscription as? TGBridgeSendStickerMessageSubscription {
let peerId = makePeerIdFromBridgeIdentifier(args.peerId)
messageSignal = mediaForSticker(documentId: args.document.documentId, account: context.account)
|> map({ media -> (EnqueueMessage?, PeerId?) in
if let media = media {
return (.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil), peerId)
return (.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil), peerId)
} else {
return (nil, nil)
}
@ -218,7 +218,7 @@ final class WatchSendMessageHandler: WatchRequestHandler {
} else if let args = subscription as? TGBridgeSendForwardedMessageSubscription {
let peerId = makePeerIdFromBridgeIdentifier(args.targetPeerId)
if let forwardPeerId = makePeerIdFromBridgeIdentifier(args.peerId) {
messageSignal = .single((.forward(source: MessageId(peerId: forwardPeerId, namespace: Namespaces.Message.Cloud, id: args.messageId), grouping: .none, attributes: []), peerId))
messageSignal = .single((.forward(source: MessageId(peerId: forwardPeerId, namespace: Namespaces.Message.Cloud, id: args.messageId), grouping: .none, attributes: [], correlationId: nil), peerId))
}
}
@ -728,7 +728,7 @@ final class WatchAudioHandler: WatchRequestHandler {
replyMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: replyToMid)
}
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: data.count, attributes: [.Audio(isVoice: true, duration: Int(duration), title: nil, performer: nil, waveform: nil)])), replyToMessageId: replyMessageId, localGroupingKey: nil)]).start()
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: data.count, attributes: [.Audio(isVoice: true, duration: Int(duration), title: nil, performer: nil, waveform: nil)])), replyToMessageId: replyMessageId, localGroupingKey: nil, correlationId: nil)]).start()
}
})
} else {