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.VoiceChatStarted" = "%1$@ started a voice chat";
"Notification.VoiceChatEnded" = "Voice chat ended (%@)"; "Notification.VoiceChatEnded" = "Voice chat ended (%@)";
"Notification.VoiceChatEndedGroup" = "%1$@ ended the voice chat (%2$@)";
"VoiceChat.Panel.TapToJoin" = "Tap to join"; "VoiceChat.Panel.TapToJoin" = "Tap to join";
"VoiceChat.Panel.Members_0" = "%@ participants"; "VoiceChat.Panel.Members_0" = "%@ participants";
@ -6445,3 +6446,13 @@ Sorry for the inconvenience.";
"VoiceChat.ReminderNotify" = "We will notify you when it starts."; "VoiceChat.ReminderNotify" = "We will notify you when it starts.";
"Checkout.SuccessfulTooltip" = "You paid %1$@ for %2$@."; "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; CGFloat baselineNudge = (lineHeight - fontLineHeight) * 0.6f;
CGRect rect = *lineFragmentRect; CGRect rect = *lineFragmentRect;
rect.size.height = lineHeight; rect.size.height = lineHeight + 2.0f;
CGRect usedRect = *lineFragmentUsedRect; CGRect usedRect = *lineFragmentUsedRect;
usedRect.size.height = MAX(lineHeight, usedRect.size.height); 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)) (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 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 |> deliverOnMainQueue).start(next: { [weak self] messageIds in
if let strongSelf = self { if let strongSelf = self {

View File

@ -825,7 +825,7 @@ public func createPollController(context: AccountContext, peer: Peer, isQuiz: Bo
dismissImpl?() 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: { 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) 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 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() 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) 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 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() 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) 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 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() 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 messages = logs.map { (name, path) -> EnqueueMessage in
let id = arc4random64() 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)]) 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() 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 messages = logs.map { (name, path) -> EnqueueMessage in
let id = arc4random64() 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)]) 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() 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 |> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self, strongSelf.traceVisibility() { if let strongSelf = self, strongSelf.traceVisibility() {
if strongSelf.messageId.peerId.namespace == Namespaces.Peer.CloudUser { 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 { } else if strongSelf.messageId.peerId.namespace == Namespaces.Peer.SecretChat {
let _ = addSecretChatMessageScreenshot(account: strongSelf.context.account, peerId: strongSelf.messageId.peerId).start() 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 return Signal { subscriber in
if let previewImage = UIImage(data: data) { if let previewImage = UIImage(data: data) {
let dimensions = previewImage.size let dimensions = previewImage.size
@ -286,7 +286,7 @@ public func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<Enqu
fileAttributes.append(.Animated) 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) 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() subscriber.putCompletion()
} else { } else {
subscriber.putError(Void()) subscriber.putError(Void())
@ -296,7 +296,7 @@ public func legacyEnqueueGifMessage(account: Account, data: Data) -> Signal<Enqu
} |> runOn(Queue.concurrentDefaultQueue()) } |> 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 return Signal { subscriber in
if let previewImage = UIImage(data: data) { if let previewImage = UIImage(data: data) {
let dimensions = previewImage.size let dimensions = previewImage.size
@ -328,7 +328,7 @@ public func legacyEnqueueVideoMessage(account: Account, data: Data) -> Signal<En
fileAttributes.append(.Animated) 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) 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() subscriber.putCompletion()
} else { } else {
subscriber.putError(Void()) subscriber.putError(Void())
@ -391,7 +391,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
} }
var text = caption ?? "" 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): case let .asset(asset):
@ -407,7 +407,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
if let timer = item.timer, timer > 0 && timer <= 60 { if let timer = item.timer, timer > 0 && timer <= 60 {
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil)) 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: case .tempFile:
break break
} }
@ -418,13 +418,13 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
arc4random_buf(&randomId, 8) arc4random_buf(&randomId, 8)
let resource = LocalFileReferenceMediaResource(localFilePath: path, randomId: randomId) 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)]) 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): case let .asset(asset):
var randomId: Int64 = 0 var randomId: Int64 = 0
arc4random_buf(&randomId, 8) arc4random_buf(&randomId, 8)
let resource = PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: arc4random64()) 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)]) 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: default:
break break
} }
@ -552,7 +552,7 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
if let timer = item.timer, timer > 0 && timer <= 60 { if let timer = item.timer, timer > 0 && timer <= 60 {
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil)) 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 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 { 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 { if let forceTheme = forceTheme {
presentationData = presentationData.withUpdated(theme: 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 presentationData in
var presentationData = presentationData var presentationData = presentationData
if let forceTheme = forceTheme { if let forceTheme = forceTheme {

View File

@ -9,11 +9,11 @@ import TelegramPresentationData
import TelegramUIPreferences import TelegramUIPreferences
import ItemListUI import ItemListUI
import PresentationDataUtils import PresentationDataUtils
import OverlayStatusController
import AccountContext import AccountContext
import AlertUI import AlertUI
import PresentationDataUtils import PresentationDataUtils
import TelegramNotices import TelegramNotices
import UndoUI
private final class DataPrivacyControllerArguments { private final class DataPrivacyControllerArguments {
let account: Account let account: Account
@ -368,7 +368,19 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state return state
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 } 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() dismissAction()
@ -422,7 +434,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state return state
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 } 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: {})])) }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]))
} }
@ -478,7 +490,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return state return state
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 } 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() dismissAction()
@ -530,7 +542,7 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
let controller = ItemListController(context: context, state: signal) let controller = ItemListController(context: context, state: signal)
presentControllerImpl = { [weak controller] c in presentControllerImpl = { [weak controller] c in
controller?.present(c, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) controller?.present(c, in: .window(.root))
} }
return controller return controller

View File

@ -443,7 +443,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|> take(1)).start(next: { previewTheme, settings in |> take(1)).start(next: { previewTheme, settings in
let saveThemeTemplateFile: (String, LocalFileMediaResource, @escaping () -> Void) -> Void = { title, resource, completion 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 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() 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 { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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 { } 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
@ -529,58 +529,58 @@ public final class ShareController: ViewController {
for peerId in peerIds { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
case let .quote(string, url): case let .quote(string, url):
for peerId in peerIds { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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]) let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)")) attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText) 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
case let .image(representations): case let .image(representations):
for peerId in peerIds { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
case let .media(mediaReference): case let .media(mediaReference):
for peerId in peerIds { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
case let .mapMedia(media): case let .mapMedia(media):
for peerId in peerIds { for peerId in peerIds {
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
if !text.isEmpty { 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)) shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
} }
case let .messages(messages): case let .messages(messages):
for peerId in peerIds { for peerId in peerIds {
var messagesToEnqueue: [EnqueueMessage] = [] var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty { 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 { 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)) 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 { for item in items {
switch item { switch item {
case let .text(text): 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): case let .media(media):
switch media { switch media {
case let .media(reference): 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) messages.append(message)
mediaMessages.append(message) mediaMessages.append(message)

View File

@ -19,30 +19,38 @@ public class OutgoingMessageInfoAttribute: MessageAttribute {
public let uniqueId: Int64 public let uniqueId: Int64
public let flags: OutgoingMessageInfoFlags public let flags: OutgoingMessageInfoFlags
public let acknowledged: Bool 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.uniqueId = uniqueId
self.flags = flags self.flags = flags
self.acknowledged = acknowledged self.acknowledged = acknowledged
self.correlationId = correlationId
} }
required public init(decoder: PostboxDecoder) { required public init(decoder: PostboxDecoder) {
self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0) self.uniqueId = decoder.decodeInt64ForKey("u", orElse: 0)
self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)) self.flags = OutgoingMessageInfoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0))
self.acknowledged = decoder.decodeInt32ForKey("ack", orElse: 0) != 0 self.acknowledged = decoder.decodeInt32ForKey("ack", orElse: 0) != 0
self.correlationId = decoder.decodeOptionalInt64ForKey("cid")
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt64(self.uniqueId, forKey: "u") encoder.encodeInt64(self.uniqueId, forKey: "u")
encoder.encodeInt32(self.flags.rawValue, forKey: "f") encoder.encodeInt32(self.flags.rawValue, forKey: "f")
encoder.encodeInt32(self.acknowledged ? 1 : 0, forKey: "ack") 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 { 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 { 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 name = "\(callId.id)_\(callId.accessHash).log.json"
let path = callLogsPath(account: account) + "/" + name 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 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 return rate
|> then(enqueueMessages(account: account, peerId: peerId, messages: [message]) |> then(enqueueMessages(account: account, peerId: peerId, messages: [message])
|> mapToSignal({ _ -> Signal<Void, NoError> in |> mapToSignal({ _ -> Signal<Void, NoError> in
@ -257,7 +257,7 @@ func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comm
})) }))
} else if !comment.isEmpty { } else if !comment.isEmpty {
return rate 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 |> mapToSignal({ _ -> Signal<Void, NoError> in
return .single(Void()) return .single(Void())
})) }))

View File

@ -982,7 +982,7 @@ public final class VoiceChatController: ViewController {
dismissController?() dismissController?()
if let strongSelf = self { 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 |> deliverOnMainQueue).start(next: { [weak self] _ in
if let strongSelf = self { 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 }) 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> { public var updateLoginTokenEvents: Signal<Void, NoError> {
return self.updateLoginTokenPipe.signal() return self.updateLoginTokenPipe.signal()
} }
private let serviceNotificationPipe = ValuePipe<String>()
public var serviceNotificationEvents: Signal<String, NoError> {
return self.serviceNotificationPipe.signal()
}
public var masterDatacenterId: Int32 { public var masterDatacenterId: Int32 {
return Int32(self.network.mtProto.datacenterId) return Int32(self.network.mtProto.datacenterId)
@ -83,8 +88,11 @@ public class UnauthorizedAccount {
self.postbox = postbox self.postbox = postbox
self.network = network self.network = network
let updateLoginTokenPipe = self.updateLoginTokenPipe let updateLoginTokenPipe = self.updateLoginTokenPipe
let serviceNotificationPipe = self.serviceNotificationPipe
self.stateManager = UnauthorizedAccountStateManager(network: network, updateLoginToken: { self.stateManager = UnauthorizedAccountStateManager(network: network, updateLoginToken: {
updateLoginTokenPipe.putNext(Void()) updateLoginTokenPipe.putNext(Void())
}, displayServiceNotification: { text in
serviceNotificationPipe.putNext(text)
}) })
network.shouldKeepConnection.set(self.shouldBeServiceTaskMaster.get() network.shouldKeepConnection.set(self.shouldBeServiceTaskMaster.get()

View File

@ -11,13 +11,13 @@ public enum EnqueueMessageGrouping {
} }
public enum EnqueueMessage { public enum EnqueueMessage {
case message(text: String, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, replyToMessageId: MessageId?, localGroupingKey: Int64?) case message(text: String, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, replyToMessageId: MessageId?, localGroupingKey: Int64?, correlationId: Int64?)
case forward(source: MessageId, grouping: EnqueueMessageGrouping, attributes: [MessageAttribute]) case forward(source: MessageId, grouping: EnqueueMessageGrouping, attributes: [MessageAttribute], correlationId: Int64?)
public func withUpdatedReplyToMessageId(_ replyToMessageId: MessageId?) -> EnqueueMessage { public func withUpdatedReplyToMessageId(_ replyToMessageId: MessageId?) -> EnqueueMessage {
switch self { switch self {
case let .message(text, attributes, mediaReference, _, localGroupingKey): case let .message(text, attributes, mediaReference, _, localGroupingKey, correlationId):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey) return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId)
case .forward: case .forward:
return self return self
} }
@ -25,21 +25,41 @@ public enum EnqueueMessage {
public func withUpdatedAttributes(_ f: ([MessageAttribute]) -> [MessageAttribute]) -> EnqueueMessage { public func withUpdatedAttributes(_ f: ([MessageAttribute]) -> [MessageAttribute]) -> EnqueueMessage {
switch self { switch self {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
return .message(text: text, attributes: f(attributes), mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey) return .message(text: text, attributes: f(attributes), mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: localGroupingKey, correlationId: correlationId)
case let .forward(source, grouping, attributes): case let .forward(source, grouping, attributes, correlationId):
return .forward(source: source, grouping: grouping, attributes: f(attributes)) return .forward(source: source, grouping: grouping, attributes: f(attributes), correlationId: correlationId)
} }
} }
public func withUpdatedGroupingKey(_ f: (Int64?) -> Int64?) -> EnqueueMessage { public func withUpdatedGroupingKey(_ f: (Int64?) -> Int64?) -> EnqueueMessage {
switch self { switch self {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: f(localGroupingKey)) return .message(text: text, attributes: attributes, mediaReference: mediaReference, replyToMessageId: replyToMessageId, localGroupingKey: f(localGroupingKey), correlationId: correlationId)
case .forward: case .forward:
return self 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 { func augmentMediaWithReference(_ mediaReference: AnyMediaReference) -> Media {
@ -139,7 +159,7 @@ private func opportunisticallyTransformOutgoingMedia(network: Network, postbox:
var hasMedia = false var hasMedia = false
loop: for message in messages { loop: for message in messages {
switch message { switch message {
case let .message(_, _, mediaReference, _, _): case let .message(_, _, mediaReference, _, _, _):
if mediaReference != nil { if mediaReference != nil {
hasMedia = true hasMedia = true
break loop break loop
@ -156,14 +176,14 @@ private func opportunisticallyTransformOutgoingMedia(network: Network, postbox:
var signals: [Signal<(Bool, EnqueueMessage), NoError>] = [] var signals: [Signal<(Bool, EnqueueMessage), NoError>] = []
for message in messages { for message in messages {
switch message { switch message {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
if let mediaReference = mediaReference { if let mediaReference = mediaReference {
signals.append(opportunisticallyTransformMessageWithMedia(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, mediaReference: mediaReference, userInteractive: userInteractive) signals.append(opportunisticallyTransformMessageWithMedia(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, mediaReference: mediaReference, userInteractive: userInteractive)
|> map { result -> (Bool, EnqueueMessage) in |> map { result -> (Bool, EnqueueMessage) in
if let result = result { 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 { } 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 { } 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) }) 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 { switch message {
case let .message(_, _, _, replyToMessageId, _): case let .message(_, _, _, replyToMessageId, _, _):
if let replyToMessageId = replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) { if let replyToMessageId = replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) {
var canBeForwarded = true var canBeForwarded = true
if replyMessage.id.namespace != Namespaces.Message.Cloud { if replyMessage.id.namespace != Namespaces.Message.Cloud {
@ -271,10 +291,10 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
} }
} }
if canBeForwarded { 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) { if let sourceMessage = forwardedMessageToBeReuploaded(transaction: transaction, id: sourceId) {
var mediaReference: AnyMediaReference? var mediaReference: AnyMediaReference?
if sourceMessage.id.peerId.namespace == Namespaces.Peer.SecretChat { if sourceMessage.id.peerId.namespace == Namespaces.Peer.SecretChat {
@ -282,7 +302,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
mediaReference = .standalone(media: media) 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 continue outer
} }
} }
@ -319,11 +339,11 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
if transformedMedia { if transformedMedia {
infoFlags.insert(.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) globallyUniqueIds.append(randomId)
switch message { switch message {
case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey): case let .message(text, requestedAttributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
var peerAutoremoveTimeout: Int32? var peerAutoremoveTimeout: Int32?
if let peer = peer as? TelegramSecretChat { if let peer = peer as? TelegramSecretChat {
var isAction = false 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)) 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) let sourceMessage = transaction.getMessage(source)
if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] { if let sourceMessage = sourceMessage, let author = sourceMessage.author ?? sourceMessage.peers[sourceMessage.id.peerId] {
if let peer = peer as? TelegramSecretChat { if let peer = peer as? TelegramSecretChat {

View File

@ -4,7 +4,7 @@ import SwiftSignalKit
import SyncCore 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] = [] var attributes: [MessageAttribute] = []
attributes.append(OutgoingChatContextResultMessageAttribute(queryId: result.queryId, id: result.id, hideVia: hideVia)) attributes.append(OutgoingChatContextResultMessageAttribute(queryId: result.queryId, id: result.id, hideVia: hideVia))
if !hideVia { if !hideVia {
@ -32,19 +32,19 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
return true return true
} }
if let media: Media = internalReference.file ?? internalReference.image { 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 { } 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 { } 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" { } 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 { } 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 { } 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 { } else {
return nil return nil
} }
@ -56,9 +56,9 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
let thumbnailResource = thumbnail.resource let thumbnailResource = thumbnail.resource
let imageDimensions = thumbnail.dimensions ?? PixelDimensions(width: 128, height: 128) 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: []) 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 { } 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" { } else if externalReference.type == "document" || externalReference.type == "gif" || externalReference.type == "audio" || externalReference.type == "voice" {
var videoThumbnails: [TelegramMediaFile.VideoThumbnail] = [] 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) 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 { } 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): case let .text(text, entities, disableUrlPreview, replyMarkup):
@ -130,21 +130,21 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
attributes.append(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): case let .mapLocation(media, replyMarkup):
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
attributes.append(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): case let .contact(media, replyMarkup):
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
attributes.append(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): case let .invoice(media, replyMarkup):
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
attributes.append(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 let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
} else { } 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)) 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 let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute
updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia]))
} else { } 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)) 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 { } 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() return .complete()
} }
} }

View File

@ -17,7 +17,7 @@ public func setSecretChatMessageAutoremoveTimeoutInteractively(account: Account,
transaction.setPeerChatState(peerId, state: updatedState) 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: default:
break 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 var updateService: UnauthorizedUpdateMessageService?
private let updateServiceDisposable = MetaDisposable() private let updateServiceDisposable = MetaDisposable()
private let updateLoginToken: () -> Void 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.network = network
self.updateLoginToken = updateLoginToken self.updateLoginToken = updateLoginToken
self.displayServiceNotification = displayServiceNotification
} }
deinit { deinit {
@ -69,11 +71,17 @@ final class UnauthorizedAccountStateManager {
if self.updateService == nil { if self.updateService == nil {
self.updateService = UnauthorizedUpdateMessageService() self.updateService = UnauthorizedUpdateMessageService()
let updateLoginToken = self.updateLoginToken let updateLoginToken = self.updateLoginToken
let displayServiceNotification = self.displayServiceNotification
self.updateServiceDisposable.set(self.updateService!.pipe.signal().start(next: { updates in self.updateServiceDisposable.set(self.updateService!.pipe.signal().start(next: { updates in
for update in updates { for update in updates {
switch update { switch update {
case .updateLoginToken: case .updateLoginToken:
updateLoginToken() updateLoginToken()
case let .updateServiceNotification(flags, _, _, message, _, _):
let popup = (flags & (1 << 0)) != 0
if popup {
displayServiceNotification(message)
}
default: default:
break break
} }

View File

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

View File

@ -1974,7 +1974,7 @@ final class SharedApplicationContext {
if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) { if let messageId = messageIdFromNotification(peerId: peerId, notification: response.notification) {
let _ = applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0)).start() 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 |> map { messageIds -> MessageId? in
if messageIds.isEmpty { if messageIds.isEmpty {
return nil return nil

View File

@ -36,6 +36,8 @@ final class UnauthorizedApplicationContext {
let isReady = Promise<Bool>() let isReady = Promise<Bool>()
var authorizationCompleted: Bool = false var authorizationCompleted: Bool = false
private var serviceNotificationEventsDisposable: Disposable?
init(apiId: Int32, apiHash: String, sharedContext: SharedAccountContextImpl, account: UnauthorizedAccount, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)])) { init(apiId: Int32, apiHash: String, sharedContext: SharedAccountContextImpl, account: UnauthorizedAccount, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)])) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
@ -71,6 +73,20 @@ final class UnauthorizedApplicationContext {
}, { result in }, { result in
ApplicationSpecificNotice.setPermissionWarning(accountManager: sharedContext.accountManager, permission: .cellularData, value: 0) 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 { if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities)) 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 }, sendSticker: { [weak self] fileReference, query, clearInput, sourceNode, sourceRect in
guard let strongSelf = self else { guard let strongSelf = self else {
return false return false
@ -1043,7 +1043,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
attributes.append(EmojiSearchQueryMessageAttribute(query: query)) 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 return true
}, sendGif: { [weak self] fileReference, sourceNode, sourceRect in }, sendGif: { [weak self] fileReference, sourceNode, sourceRect in
if let strongSelf = self { 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 return true
}, sendBotContextResultAsGif: { [weak self] collection, result, sourceNode, sourceRect in }, sendBotContextResultAsGif: { [weak self] collection, result, sourceNode, sourceRect in
@ -1363,7 +1363,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|> deliverOnMainQueue).start(next: { coordinate in |> deliverOnMainQueue).start(next: { coordinate in
if let strongSelf = self { if let strongSelf = self {
if let coordinate = coordinate { 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 { } 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)) 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) let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId)
|> deliverOnMainQueue).start(next: { peer in |> deliverOnMainQueue).start(next: { peer in
if let peer = peer as? TelegramUser, let phone = peer.phone, !phone.isEmpty { 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 { if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities)) 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 }, openInstantPage: { [weak self] message, associatedData in
if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.effectiveNavigationController, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) { 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 items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ShareMenu_Send, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
if let strongSelf = self { 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.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 { if case .pinnedMessages = self.presentationInterfaceState.subject {
@ -4480,7 +4482,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} else { } else {
isScheduledMessages = false 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 var options = transition.options
let _ = options.insert(.Synchronous) let _ = options.insert(.Synchronous)
let _ = options.insert(.LowLatency) let _ = options.insert(.LowLatency)
@ -4506,9 +4508,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var scrollToItem: ListViewScrollToItem? var scrollToItem: ListViewScrollToItem?
if isScheduledMessages, let insertedIndex = insertedIndex { 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 { } 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)? var stationaryItemRange: (Int, Int)?
@ -4566,12 +4568,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var forwardedMessages: [[EnqueueMessage]] = [] var forwardedMessages: [[EnqueueMessage]] = []
var forwardSourcePeerIds = Set<PeerId>() var forwardSourcePeerIds = Set<PeerId>()
for message in transformedMessages { for message in transformedMessages {
if case let .forward(source, _, _) = message { if case let .forward(source, _, _, _) = message {
forwardSourcePeerIds.insert(source.peerId) forwardSourcePeerIds.insert(source.peerId)
var added = false var added = false
if var last = forwardedMessages.last { 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) last.append(message)
added = true added = true
} }
@ -5371,7 +5373,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if !entities.isEmpty { if !entities.isEmpty {
attributes.append(TextEntitiesMessageAttribute(entities: entities)) 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 }, sendBotStart: { [weak self] payload in
@ -8308,7 +8310,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
private func editMessageMediaWithMessages(_ messages: [EnqueueMessage]) { 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 self.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
var state = state var state = state
if let editMessageState = state.editMessageState, case let .media(options) = editMessageState.content, !options.isEmpty { 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 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) messages.append(message)
} }
if let _ = groupingKey, messages.count % 10 == 0 { if let _ = groupingKey, messages.count % 10 == 0 {
@ -8899,7 +8901,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return return
} }
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId 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({ strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self { if let strongSelf = self {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, { 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) 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]) strongSelf.sendMessages([message])
} else { } else {
let contactController = strongSelf.context.sharedContext.makeDeviceContactInfoController(context: strongSelf.context, subject: .filter(peer: peerAndContactData.0, contactId: nil, contactData: contactData, completion: { peer, contactData in 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]) strongSelf.sendMessages([message])
} }
}), completed: nil, cancelled: nil) }), completed: nil, cancelled: nil)
@ -9406,7 +9408,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let value = value { 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 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 { 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 return false
}), in: .current) }), in: .current)
@ -9427,9 +9429,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let defaultReplyMessageId = defaultReplyMessageId { if let defaultReplyMessageId = defaultReplyMessageId {
switch message { switch message {
case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey): case let .message(text, attributes, mediaReference, replyToMessageId, localGroupingKey, correlationId):
if replyToMessageId == nil { 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: case .forward:
break break
@ -9598,7 +9600,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
fileAttributes.append(.ImageSize(size: PixelDimensions(size))) 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 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 let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({ 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?.tap()
strongSelf.recorderFeedback = nil 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] let transformedMessages: [EnqueueMessage]
if let silentPosting = silentPosting { if let silentPosting = silentPosting {
@ -10628,7 +10630,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}), in: .current) }), in: .current)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messages.map { message -> EnqueueMessage in 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 |> deliverOnMainQueue).start(next: { messageIds in
if let strongSelf = self { if let strongSelf = self {
@ -10986,7 +10988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
Queue.mainQueue().async { Queue.mainQueue().async {
unblockingPeer.set(false) unblockingPeer.set(false)
if let strongSelf = self, restartBot { 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()) })).start())

View File

@ -393,6 +393,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var expandedInputDimNode: ASDisplayNode? private var expandedInputDimNode: ASDisplayNode?
private var dropDimNode: ASDisplayNode? private var dropDimNode: ASDisplayNode?
let messageTransitionNode: ChatMessageTransitionNode
private var containerLayoutAndNavigationBarHeight: (ContainerViewLayout, CGFloat)? private var containerLayoutAndNavigationBarHeight: (ContainerViewLayout, CGFloat)?
@ -501,6 +503,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.navigationBarSeparatorNode = ASDisplayNode() self.navigationBarSeparatorNode = ASDisplayNode()
self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor
self.messageTransitionNode = ChatMessageTransitionNode(listNode: self.historyNode)
super.init() super.init()
@ -593,6 +597,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.addSubnode(self.navigationBarBackroundNode) self.addSubnode(self.navigationBarBackroundNode)
self.addSubnode(self.navigationBarSeparatorNode) self.addSubnode(self.navigationBarSeparatorNode)
self.addSubnode(self.messageTransitionNode)
if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding { if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding {
self.navigationBarBackroundNode.isHidden = true self.navigationBarBackroundNode.isHidden = true
self.navigationBarSeparatorNode.isHidden = true self.navigationBarSeparatorNode.isHidden = true
@ -1150,7 +1157,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var dismissedInputPanelNode: ASDisplayNode? var dismissedInputPanelNode: ASDisplayNode?
var dismissedSecondaryInputPanelNode: ASDisplayNode? var dismissedSecondaryInputPanelNode: ASDisplayNode?
var dismissedAccessoryPanelNode: ASDisplayNode? var dismissedAccessoryPanelNode: AccessoryPanelNode?
var dismissedInputContextPanelNode: ChatInputContextPanelNode? var dismissedInputContextPanelNode: ChatInputContextPanelNode?
var dismissedOverlayContextPanelNode: ChatInputContextPanelNode? var dismissedOverlayContextPanelNode: ChatInputContextPanelNode?
@ -1743,6 +1750,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let inputPanelFrame = inputPanelFrame { if let inputPanelFrame = inputPanelFrame {
transitionTargetY = inputPanelFrame.minY 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 transition.updateFrame(node: dismissedAccessoryPanelNode, frame: CGRect(origin: CGPoint(x: 0.0, y: transitionTargetY), size: dismissedAccessoryPanelNode.frame.size), completion: { _ in
frameCompleted = true frameCompleted = true
completed() completed()
@ -2607,7 +2617,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines) let trimmedInputText = effectiveInputText.string.trimmingCharacters(in: .whitespacesAndNewlines)
let peerId = effectivePresentationInterfaceState.chatLocation.peerId let peerId = effectivePresentationInterfaceState.chatLocation.peerId
if peerId.namespace != Namespaces.Peer.SecretChat, let interactiveEmojis = self.interactiveEmojis, interactiveEmojis.emojis.contains(trimmedInputText) { 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 { } else {
let inputText = convertMarkdownToAttributes(effectiveInputText) let inputText = convertMarkdownToAttributes(effectiveInputText)
@ -2624,7 +2634,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else { } else {
webpage = self.chatPresentationInterfaceState.urlPreview?.1 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 { if let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
for id in 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 let historyView = strongSelf.historyView {
if historyView.filteredEntries.isEmpty { if historyView.filteredEntries.isEmpty {
if let firstEntry = historyView.originalView.entries.first { if let firstEntry = historyView.originalView.entries.first {
var isPeerJoined = false
var emptyType = ChatHistoryNodeLoadState.EmptyType.generic var emptyType = ChatHistoryNodeLoadState.EmptyType.generic
for media in firstEntry.message.media { for media in firstEntry.message.media {
if let action = media as? TelegramMediaAction { if let action = media as? TelegramMediaAction {
@ -1893,6 +1892,28 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} else if transition.scrolledToSomeIndex { } else if transition.scrolledToSomeIndex {
self?.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.hasActiveTransition = false
strongSelf.dequeueHistoryViewTransitions() strongSelf.dequeueHistoryViewTransitions()
@ -2245,4 +2266,11 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
}) })
self.selectionScrollDisplayLink?.isPaused = false 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 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 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() let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
} }

View File

@ -233,6 +233,23 @@ class ChatMessageBackground: ASDisplayNode {
self.imageNode.image = image self.imageNode.image = image
self.outlineImageNode.image = outlineImage 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 { 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 mainContainerNode: ContextControllerSourceNode
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
private let backgroundNode: ChatMessageBackground private let backgroundNode: ChatMessageBackground
@ -553,6 +553,40 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") 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) { override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
super.animateInsertion(currentTimestamp, duration: duration, short: short) 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() { override func didLoad() {
super.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)) 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) { override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
if short { 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? { override func getStatusNode() -> ASDisplayNode? {
return self.statusNode 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 var currentTextInputBackgroundImage: (UIColor, UIColor, CGFloat, UIImage)?
private func textInputBackgroundImage(backgroundColor: UIColor, strokeColor: UIColor, diameter: CGFloat) -> UIImage? { private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackgroundColor: UIColor?, strokeColor: UIColor, diameter: CGFloat) -> UIImage? {
if let current = currentTextInputBackgroundImage { if let backgroundColor = backgroundColor, let current = currentTextInputBackgroundImage {
if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) { if current.0.isEqual(backgroundColor) && current.1.isEqual(strokeColor) && current.2.isEqual(to: diameter) {
return current.3 return current.3
} }
} }
let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
context.setFillColor(backgroundColor.cgColor) if let backgroundColor = backgroundColor {
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter)) context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setBlendMode(.clear) } else {
context.setFillColor(UIColor.clear.cgColor) 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.fillEllipse(in: CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
context.setBlendMode(.normal) context.setBlendMode(.normal)
context.setStrokeColor(strokeColor.cgColor) context.setStrokeColor(strokeColor.cgColor)
let strokeWidth: CGFloat = 1.0 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)) 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) })?.stretchableImage(withLeftCapWidth: Int(diameter) / 2, topCapHeight: Int(diameter) / 2)
if let image = image { if let image = image {
currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, image) if let backgroundColor = backgroundColor {
currentTextInputBackgroundImage = (backgroundColor, strokeColor, diameter, image)
}
return image return image
} else { } else {
return nil return nil
@ -205,6 +217,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var textInputNode: EditableTextNode? var textInputNode: EditableTextNode?
let textInputBackgroundNode: ASImageNode let textInputBackgroundNode: ASImageNode
private var transparentTextInputBackgroundImage: UIImage?
let actionButtons: ChatTextInputActionButtonsNode let actionButtons: ChatTextInputActionButtonsNode
var mediaRecordingAccessibilityArea: AccessibilityAreaNode? var mediaRecordingAccessibilityArea: AccessibilityAreaNode?
private let counterTextNode: ImmediateTextNode private let counterTextNode: ImmediateTextNode
@ -636,7 +649,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let maxNumberOfLines = min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22) 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)) textFieldHeight = max(textFieldMinHeight, min(updatedMaxHeight, unboundTextFieldHeight))
} else { } else {
@ -779,7 +792,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
backgroundColor = interfaceState.theme.chat.inputPanel.panelBackgroundColor 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) self.searchLayoutClearImageNode.image = PresentationResourcesChat.chatInputTextFieldClearImage(interfaceState.theme)
@ -2152,5 +2166,28 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
return nil 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])]) 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 let scheduleTime: Int32? = scheduleTimestamp > 0 ? scheduleTimestamp : nil

View File

@ -67,7 +67,7 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
params.dismissInput() params.dismissInput()
let controllerParams = LocationViewParams(sendLiveLocation: { location in 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) params.enqueueMessage(outMessage)
}, stopLiveLocation: { messageId in }, stopLiveLocation: { messageId in
params.context.liveLocationManager?.cancelLiveLocation(peerId: messageId?.peerId ?? params.message.id.peerId) 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 { if let peer = peer as? TelegramUser, let _ = peer.botInfo {
strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: block).start()) strongSelf.activeActionDisposable.set(requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.id, isBlocked: block).start())
if !block { 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 { if let navigationController = strongSelf.controller?.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id))) 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: case .help:
text = "/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 { if let navigationController = strongSelf.controller?.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(strongSelf.peerId))) 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) strongSelf.headerNode.navigationButtonContainer.performAction?(.selectionDone)
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peerId, messages: messageIds.map { id -> EnqueueMessage in 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 |> deliverOnMainQueue).start(next: { [weak self] messageIds in
if let strongSelf = self { if let strongSelf = self {

View File

@ -48,10 +48,12 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.titleNode = ImmediateTextNode() self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1 self.titleNode.maximumNumberOfLines = 1
self.titleNode.displaysAsynchronously = false 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 = ImmediateTextNode()
self.textNode.maximumNumberOfLines = 1 self.textNode.maximumNumberOfLines = 1
self.textNode.displaysAsynchronously = false 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 = TransformImageNode()
self.imageNode.contentAnimations = [.subsequentUpdates] self.imageNode.contentAnimations = [.subsequentUpdates]
@ -162,8 +164,8 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
isMedia = false isMedia = false
} }
strongSelf.titleNode.attributedText = NSAttributedString(string: authorName, font: Font.medium(15.0), textColor: strongSelf.theme.chat.inputPanel.panelControlAccentColor) 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(15.0), textColor: isMedia ? strongSelf.theme.chat.inputPanel.secondaryTextColor : strongSelf.theme.chat.inputPanel.primaryTextColor) 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 let headerString: String
if let message = message, message.flags.contains(.Incoming), let author = message.author { 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.closeButton.frame = closeButtonFrame
self.actionArea.frame = CGRect(origin: CGPoint(x: leftInset, y: 2.0), size: CGSize(width: closeButtonFrame.minX - leftInset, height: bounds.height)) 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 var imageTextInset: CGFloat = 0.0
if !self.imageNode.isHidden { if !self.imageNode.isHidden {
imageTextInset = 9.0 + 35.0 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)) 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)) 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() { @objc func closePressed() {

View File

@ -1121,7 +1121,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
if !found { if !found {
let controllerParams = LocationViewParams(sendLiveLocation: { location in 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) // params.enqueueMessage(outMessage)
}, stopLiveLocation: { messageId in }, stopLiveLocation: { messageId in
if let messageId = messageId { 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 { if args.replyToMid != 0, let peerId = peerId {
replyMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: args.replyToMid) 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 { } else if let args = subscription as? TGBridgeSendLocationMessageSubscription, let location = args.location {
let peerId = makePeerIdFromBridgeIdentifier(args.peerId) 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) 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 { } else if let args = subscription as? TGBridgeSendStickerMessageSubscription {
let peerId = makePeerIdFromBridgeIdentifier(args.peerId) let peerId = makePeerIdFromBridgeIdentifier(args.peerId)
messageSignal = mediaForSticker(documentId: args.document.documentId, account: context.account) messageSignal = mediaForSticker(documentId: args.document.documentId, account: context.account)
|> map({ media -> (EnqueueMessage?, PeerId?) in |> map({ media -> (EnqueueMessage?, PeerId?) in
if let media = media { 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 { } else {
return (nil, nil) return (nil, nil)
} }
@ -218,7 +218,7 @@ final class WatchSendMessageHandler: WatchRequestHandler {
} else if let args = subscription as? TGBridgeSendForwardedMessageSubscription { } else if let args = subscription as? TGBridgeSendForwardedMessageSubscription {
let peerId = makePeerIdFromBridgeIdentifier(args.targetPeerId) let peerId = makePeerIdFromBridgeIdentifier(args.targetPeerId)
if let forwardPeerId = makePeerIdFromBridgeIdentifier(args.peerId) { 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) 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 { } else {