mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Paid media content
This commit is contained in:
parent
2292e8cac8
commit
40a4183095
@ -12318,6 +12318,7 @@ Sorry for the inconvenience.";
|
||||
"Stars.Transfer.PurchasedText" = "You acquired **%1$@** in **%2$@** for **%3$@**.";
|
||||
"Stars.Transfer.Purchased.Stars_1" = "%@ Star";
|
||||
"Stars.Transfer.Purchased.Stars_any" = "%@ Stars";
|
||||
"Stars.Transfer.UnlockedText" = "You unlocked media for **%1$@**.";
|
||||
"Stars.Transfer.UnlockInfo" = "Do you want to unlock media for **%1$@**?";
|
||||
|
||||
"Stars.Transfer.Balance" = "Balance";
|
||||
@ -12351,6 +12352,7 @@ Sorry for the inconvenience.";
|
||||
"Stars.BotRevenue.Revenue.Title" = "Revenue";
|
||||
"Stars.BotRevenue.Proceeds.Title" = "Proceeds Overview";
|
||||
"Stars.BotRevenue.Proceeds.Available" = "Available Balance";
|
||||
"Stars.BotRevenue.Proceeds.Current" = "Total Balance";
|
||||
"Stars.BotRevenue.Proceeds.Total" = "Total Lifetime Proceeds";
|
||||
"Stars.BotRevenue.Proceeds.Info" = "Stars from your total balance become available for spending on ads and rewards 21 days after they are earned.";
|
||||
|
||||
|
@ -337,6 +337,12 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
||||
if messageText.isEmpty, case let .Loaded(content) = webpage.content {
|
||||
messageText = content.displayUrl
|
||||
}
|
||||
case _ as TelegramMediaPaidContent:
|
||||
if message.text.isEmpty {
|
||||
messageText = "Paid Media"
|
||||
} else {
|
||||
messageText = "🖼 \(messageText)"
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
@ -111,7 +111,10 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
||||
}
|
||||
}
|
||||
for media in message.media {
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
if let paidContent = media as? TelegramMediaPaidContent, let extendedMedia = paidContent.extendedMedia.first, case let .full(fullMedia) = extendedMedia {
|
||||
standalone = true
|
||||
galleryMedia = fullMedia
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
standalone = true
|
||||
galleryMedia = fullMedia
|
||||
} else if let action = media as? TelegramMediaAction {
|
||||
|
@ -1622,7 +1622,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
||||
|
||||
var hasExternalShare = true
|
||||
for media in currentMessage.media {
|
||||
if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||
if let _ = media as? TelegramMediaPaidContent {
|
||||
hasExternalShare = false
|
||||
break
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||
hasExternalShare = false
|
||||
break
|
||||
}
|
||||
|
@ -44,7 +44,9 @@ private func tagsForMessage(_ message: Message) -> MessageTags? {
|
||||
}
|
||||
|
||||
private func galleryMediaForMedia(media: Media) -> Media? {
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
if let paidContent = media as? TelegramMediaPaidContent, let extendedMedia = paidContent.extendedMedia.first, case let .full(fullMedia) = extendedMedia {
|
||||
return fullMedia
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
return fullMedia
|
||||
} else if let media = media as? TelegramMediaImage {
|
||||
return media
|
||||
|
@ -140,7 +140,9 @@ class ChatImageGalleryItem: GalleryItem {
|
||||
|
||||
node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret)
|
||||
for media in self.message.media {
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia, let image = fullMedia as? TelegramMediaImage {
|
||||
if let paidContent = media as? TelegramMediaPaidContent, let extendedMedia = paidContent.extendedMedia.first, case let .full(fullMedia) = extendedMedia, let image = fullMedia as? TelegramMediaImage {
|
||||
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia, let image = fullMedia as? TelegramMediaImage {
|
||||
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
||||
} else if let image = media as? TelegramMediaImage {
|
||||
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
||||
|
@ -942,6 +942,7 @@
|
||||
NSInteger num = 0;
|
||||
bool grouping = selectionContext.grouping;
|
||||
|
||||
NSNumber *price;
|
||||
bool hasAnyTimers = false;
|
||||
if (editingContext != nil || grouping)
|
||||
{
|
||||
@ -950,6 +951,9 @@
|
||||
if ([editingContext timerForItem:asset] != nil) {
|
||||
hasAnyTimers = true;
|
||||
}
|
||||
if (price == nil) {
|
||||
price = [editingContext priceForItem:asset];
|
||||
}
|
||||
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:asset];
|
||||
if ([adjustments isKindOfClass:[TGVideoEditAdjustments class]]) {
|
||||
TGVideoEditAdjustments *videoAdjustments = (TGVideoEditAdjustments *)adjustments;
|
||||
@ -1057,6 +1061,9 @@
|
||||
else if (groupedId != nil && !hasAnyTimers)
|
||||
dict[@"groupedId"] = groupedId;
|
||||
|
||||
if (price != nil)
|
||||
dict[@"price"] = price;
|
||||
|
||||
if (spoiler) {
|
||||
dict[@"spoiler"] = @true;
|
||||
}
|
||||
@ -1137,6 +1144,9 @@
|
||||
else if (groupedId != nil && !hasAnyTimers)
|
||||
dict[@"groupedId"] = groupedId;
|
||||
|
||||
if (price != nil)
|
||||
dict[@"price"] = price;
|
||||
|
||||
if (spoiler) {
|
||||
dict[@"spoiler"] = @true;
|
||||
}
|
||||
@ -1261,6 +1271,9 @@
|
||||
if (groupedId != nil)
|
||||
dict[@"groupedId"] = groupedId;
|
||||
|
||||
if (price != nil)
|
||||
dict[@"price"] = price;
|
||||
|
||||
if (spoiler) {
|
||||
dict[@"spoiler"] = @true;
|
||||
}
|
||||
@ -1334,6 +1347,9 @@
|
||||
else if (groupedId != nil && !hasAnyTimers)
|
||||
dict[@"groupedId"] = groupedId;
|
||||
|
||||
if (price != nil)
|
||||
dict[@"price"] = price;
|
||||
|
||||
if (spoiler) {
|
||||
dict[@"spoiler"] = @true;
|
||||
}
|
||||
@ -1415,6 +1431,9 @@
|
||||
if (timer != nil)
|
||||
dict[@"timer"] = timer;
|
||||
|
||||
if (price != nil)
|
||||
dict[@"price"] = price;
|
||||
|
||||
if (spoiler) {
|
||||
dict[@"spoiler"] = @true;
|
||||
}
|
||||
|
@ -134,13 +134,15 @@ private final class LegacyAssetItemWrapper: NSObject {
|
||||
let item: LegacyAssetItem
|
||||
let timer: Int?
|
||||
let spoiler: Bool?
|
||||
let price: Int64?
|
||||
let groupedId: Int64?
|
||||
let uniqueId: String?
|
||||
|
||||
init(item: LegacyAssetItem, timer: Int?, spoiler: Bool?, groupedId: Int64?, uniqueId: String?) {
|
||||
init(item: LegacyAssetItem, timer: Int?, spoiler: Bool?, price: Int64?, groupedId: Int64?, uniqueId: String?) {
|
||||
self.item = item
|
||||
self.timer = timer
|
||||
self.spoiler = spoiler
|
||||
self.price = price
|
||||
self.groupedId = groupedId
|
||||
self.uniqueId = uniqueId
|
||||
|
||||
@ -159,6 +161,9 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
return nil
|
||||
}
|
||||
} ?? []
|
||||
|
||||
let price = dict["price"] as? Int64
|
||||
|
||||
if (dict["type"] as! NSString) == "editedPhoto" || (dict["type"] as! NSString) == "capturedPhoto" {
|
||||
let image = dict["image"] as! UIImage
|
||||
let thumbnail = dict["previewImage"] as? UIImage
|
||||
@ -168,10 +173,10 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
let url: String? = (dict["url"] as? String) ?? (dict["url"] as? URL)?.path
|
||||
if let url = url {
|
||||
let dimensions = image.size
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: 4.0), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: false, asAnimation: true, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: 4.0), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: false, asAnimation: true, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
}
|
||||
} else {
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
}
|
||||
return result
|
||||
} else if (dict["type"] as! NSString) == "cloudPhoto" {
|
||||
@ -192,9 +197,9 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
name = customName
|
||||
}
|
||||
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .file(data: .asset(asset.backingAsset), thumbnail: thumbnail, mimeType: mimeType, name: name, caption: caption), timer: nil, spoiler: nil, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .file(data: .asset(asset.backingAsset), thumbnail: thumbnail, mimeType: mimeType, name: name, caption: caption), timer: nil, spoiler: nil, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
} else {
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .asset(asset.backingAsset), thumbnail: thumbnail, caption: caption, stickers: []), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .asset(asset.backingAsset), thumbnail: thumbnail, caption: caption, stickers: []), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
}
|
||||
return result
|
||||
} else if (dict["type"] as! NSString) == "file" {
|
||||
@ -215,12 +220,12 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
let dimensions = (dict["dimensions"]! as AnyObject).cgSizeValue!
|
||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
||||
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: tempFileUrl.path, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: nil, caption: caption, asFile: false, asAnimation: true, stickers: []), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: tempFileUrl.path, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: nil, caption: caption, asFile: false, asAnimation: true, stickers: []), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
return result
|
||||
}
|
||||
|
||||
var result: [AnyHashable: Any] = [:]
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .file(data: .tempFile(tempFileUrl.path), thumbnail: thumbnail, mimeType: mimeType, name: name, caption: caption), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .file(data: .tempFile(tempFileUrl.path), thumbnail: thumbnail, mimeType: mimeType, name: name, caption: caption), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
return result
|
||||
}
|
||||
} else if (dict["type"] as! NSString) == "video" {
|
||||
@ -232,13 +237,13 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
|
||||
if let asset = dict["asset"] as? TGMediaAsset {
|
||||
var result: [AnyHashable: Any] = [:]
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .asset(asset), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .asset(asset), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
return result
|
||||
} else if let url = (dict["url"] as? String) ?? (dict["url"] as? URL)?.absoluteString {
|
||||
let dimensions = (dict["dimensions"]! as AnyObject).cgSizeValue!
|
||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
||||
var result: [AnyHashable: Any] = [:]
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
return result
|
||||
}
|
||||
} else if (dict["type"] as! NSString) == "cameraVideo" {
|
||||
@ -254,7 +259,7 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
||||
let dimensions = previewImage.pixelSize()
|
||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
||||
var result: [AnyHashable: Any] = [:]
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -356,6 +361,15 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
return Signal { subscriber in
|
||||
let disposable = SSignal.combineSignals(signals).start(next: { anyValues in
|
||||
var messages: [LegacyAssetPickerEnqueueMessage] = []
|
||||
|
||||
struct EnqueuePaidMessage {
|
||||
var price: Int64
|
||||
var text: String
|
||||
var entities: [MessageTextEntity]
|
||||
var media: [Media]
|
||||
}
|
||||
|
||||
var paidMessage: EnqueuePaidMessage?
|
||||
|
||||
outer: for item in (anyValues as! NSArray) {
|
||||
if let item = (item as? NSDictionary)?.object(forKey: "item") as? LegacyAssetItemWrapper {
|
||||
@ -436,7 +450,26 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
}
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .asset(asset):
|
||||
@ -510,7 +543,25 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -560,7 +611,25 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: false))
|
||||
}
|
||||
}
|
||||
case .tempFile:
|
||||
break
|
||||
@ -612,7 +681,25 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: true))
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: true))
|
||||
}
|
||||
case let .asset(asset):
|
||||
var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
@ -647,7 +734,25 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: true))
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: true))
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -822,11 +927,58 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
||||
}
|
||||
}
|
||||
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: asFile))
|
||||
if let price = item.price {
|
||||
if var current = paidMessage {
|
||||
if current.text.isEmpty && !text.string.isEmpty {
|
||||
current.text = text.string
|
||||
current.entities = entities
|
||||
}
|
||||
current.media.append(media)
|
||||
paidMessage = current
|
||||
} else {
|
||||
paidMessage = EnqueuePaidMessage(
|
||||
price: price,
|
||||
text: text.string,
|
||||
entities: entities,
|
||||
media: [media]
|
||||
)
|
||||
}
|
||||
} else {
|
||||
messages.append(LegacyAssetPickerEnqueueMessage(message: .message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: item.groupedId, correlationId: nil, bubbleUpEmojiOrStickersets: bubbleUpEmojiOrStickersets), uniqueId: item.uniqueId, isFile: asFile))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let paidMessage {
|
||||
var attributes: [MessageAttribute] = []
|
||||
if !paidMessage.entities.isEmpty {
|
||||
attributes.append(TextEntitiesMessageAttribute(entities: paidMessage.entities))
|
||||
}
|
||||
messages.append(
|
||||
LegacyAssetPickerEnqueueMessage(
|
||||
message: .message(
|
||||
text: paidMessage.text,
|
||||
attributes: attributes,
|
||||
inlineStickers: [:],
|
||||
mediaReference: .standalone(
|
||||
media: TelegramMediaPaidContent(
|
||||
amount: paidMessage.price,
|
||||
extendedMedia: paidMessage.media.map { .full(media: $0) }
|
||||
)),
|
||||
threadId: nil,
|
||||
replyToMessageId: nil,
|
||||
replyToStoryId: nil,
|
||||
localGroupingKey: nil,
|
||||
correlationId: nil,
|
||||
bubbleUpEmojiOrStickersets: []
|
||||
),
|
||||
uniqueId: nil,
|
||||
isFile: false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
subscriber.putNext(messages)
|
||||
subscriber.putCompletion()
|
||||
}, error: { _ in
|
||||
|
@ -552,9 +552,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
let priceSignal = Signal<Int64?, NoError> { subscriber in
|
||||
if let signal = editingContext.priceSignal(forIdentifier: asset.localIdentifier) {
|
||||
let disposable = signal.start(next: { next in
|
||||
if let next = next as? Int64 {
|
||||
subscriber.putNext(next)
|
||||
}
|
||||
subscriber.putNext(next as? Int64)
|
||||
}, error: { _ in
|
||||
}, completed: nil)!
|
||||
|
||||
@ -681,6 +679,10 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
}
|
||||
backgroundNode.addSubnode(labelNode)
|
||||
backgroundNode.addSubnode(iconNode)
|
||||
|
||||
self.priceBackgroundNode = backgroundNode
|
||||
self.priceLabelNode = labelNode
|
||||
self.priceIconNode = iconNode
|
||||
}
|
||||
labelNode.attributedText = NSAttributedString(string: "\(price)", font: Font.semibold(15.0), textColor: .white)
|
||||
|
||||
|
@ -1838,6 +1838,21 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
}
|
||||
|
||||
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||
var price: Int64?
|
||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||
if price == nil, let itemPrice = editingContext.price(for: item) as? Int64 {
|
||||
price = itemPrice
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let price, let item = item as? TGMediaEditableItem {
|
||||
editingContext.setPrice(NSNumber(value: price), for: item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -2013,7 +2028,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
self.updateSelectionState(count: Int32(selectionContext.count()))
|
||||
|
||||
|
||||
if case let .assets(_, mode) = self.subject, case .createSticker = mode {
|
||||
let _ = cutoutAvailability(context: context).startStandalone()
|
||||
}
|
||||
@ -2434,9 +2448,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
var hasSpoilers = false
|
||||
var price: Int64?
|
||||
var hasGeneric = false
|
||||
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
||||
if price == nil, let itemPrice = editingContext.price(for: item) as? Int64 {
|
||||
price = itemPrice
|
||||
}
|
||||
if editingContext.spoiler(for: item) {
|
||||
hasSpoilers = true
|
||||
} else {
|
||||
@ -2456,8 +2474,11 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> map { [weak self] grouped, isCaptionAboveMediaAvailable -> ContextController.Items in
|
||||
guard let self else {
|
||||
return ContextController.Items(content: .list([]))
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
if !hasSpoilers {
|
||||
if !hasSpoilers && price == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: selectionCount > 1 ? strings.Attachment_SendAsFiles : strings.Attachment_SendAsFile, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/File"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
@ -2466,42 +2487,45 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self?.controllerNode.send(asFile: true, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
||||
})))
|
||||
}
|
||||
if selectionCount > 1 {
|
||||
// items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
||||
// return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/GroupingOff"), color: theme.contextMenu.primaryColor)
|
||||
// }, action: { [weak self] _, f in
|
||||
// f(.default)
|
||||
//
|
||||
// self?.groupedValue = false
|
||||
// self?.controllerNode.send(asFile: false, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
||||
// })))
|
||||
|
||||
if !items.isEmpty {
|
||||
items.append(.separator)
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Attachment_Grouped, icon: { theme in
|
||||
if !grouped {
|
||||
return nil
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
if selectionCount > 1, price == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/GroupingOff"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
self?.groupedValue = true
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Attachment_Ungrouped, icon: { theme in
|
||||
if grouped {
|
||||
return nil
|
||||
}
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
self?.groupedValue = false
|
||||
self?.controllerNode.send(asFile: false, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
||||
})))
|
||||
|
||||
// if !items.isEmpty {
|
||||
// items.append(.separator)
|
||||
// }
|
||||
// items.append(.action(ContextMenuActionItem(text: strings.Attachment_Grouped, icon: { theme in
|
||||
// if !grouped {
|
||||
// return nil
|
||||
// }
|
||||
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
// }, action: { [weak self] _, f in
|
||||
// f(.default)
|
||||
//
|
||||
// self?.groupedValue = true
|
||||
// })))
|
||||
// items.append(.action(ContextMenuActionItem(text: strings.Attachment_Ungrouped, icon: { theme in
|
||||
// if grouped {
|
||||
// return nil
|
||||
// }
|
||||
// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
|
||||
// }, action: { [weak self] _, f in
|
||||
// f(.default)
|
||||
//
|
||||
// self?.groupedValue = false
|
||||
// })))
|
||||
}
|
||||
|
||||
let isPaidAvailable = !"".isEmpty
|
||||
var isPaidAvailable = false
|
||||
if let peer = self.peer, case let .channel(channel) = peer, case .broadcast = channel.info {
|
||||
isPaidAvailable = true
|
||||
}
|
||||
if isSpoilerAvailable || isPaidAvailable || (selectionCount > 0 && isCaptionAboveMediaAvailable) {
|
||||
if !items.isEmpty {
|
||||
items.append(.separator)
|
||||
@ -2509,7 +2533,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
if isCaptionAboveMediaAvailable {
|
||||
var mediaCaptionIsAbove = false
|
||||
if let interaction = self?.interaction {
|
||||
if let interaction = self.interaction {
|
||||
mediaCaptionIsAbove = interaction.captionIsAboveMedia
|
||||
}
|
||||
|
||||
@ -2526,7 +2550,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
})))
|
||||
}
|
||||
if isSpoilerAvailable {
|
||||
if isSpoilerAvailable && price == nil {
|
||||
items.append(.action(ContextMenuActionItem(text: hasGeneric ? strings.Attachment_EnableSpoiler : strings.Attachment_DisableSpoiler, icon: { _ in return nil }, iconAnimation: ContextMenuActionItem.IconAnimation(
|
||||
name: "anim_spoiler",
|
||||
loop: true
|
||||
@ -2544,7 +2568,16 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
})))
|
||||
}
|
||||
if isPaidAvailable {
|
||||
items.append(.action(ContextMenuActionItem(text: "Make This Content Paid", icon: { theme in
|
||||
let title: String
|
||||
let titleLayout: ContextMenuActionItemTextLayout
|
||||
if let price {
|
||||
title = "Edit Price"
|
||||
titleLayout = .secondLineWithValue("\(price) Stars")
|
||||
} else {
|
||||
title = "Make This Content Paid"
|
||||
titleLayout = .singleLine
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: title, textLayout: titleLayout, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
@ -130,12 +130,27 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.spoilerDisposable.set((spoilerSignal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] hasSpoiler in
|
||||
let priceSignal = Signal<Int64?, NoError> { subscriber in
|
||||
if let signal = editingState.priceSignal(forIdentifier: asset.uniqueIdentifier) {
|
||||
let disposable = signal.start(next: { next in
|
||||
subscriber.putNext(next as? Int64)
|
||||
}, error: { _ in
|
||||
}, completed: nil)!
|
||||
|
||||
return ActionDisposable {
|
||||
disposable.dispose()
|
||||
}
|
||||
} else {
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
self.spoilerDisposable.set((combineLatest(spoilerSignal, priceSignal)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] hasSpoiler, price in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateHasSpoiler(hasSpoiler)
|
||||
strongSelf.updateHasSpoiler(hasSpoiler, price: price)
|
||||
}))
|
||||
}
|
||||
|
||||
@ -163,14 +178,14 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
private var didSetupSpoiler = false
|
||||
private func updateHasSpoiler(_ hasSpoiler: Bool) {
|
||||
private func updateHasSpoiler(_ hasSpoiler: Bool, price: Int64?) {
|
||||
var animated = true
|
||||
if !self.didSetupSpoiler {
|
||||
animated = false
|
||||
self.didSetupSpoiler = true
|
||||
}
|
||||
|
||||
if hasSpoiler {
|
||||
if hasSpoiler || price != nil {
|
||||
if self.spoilerNode == nil {
|
||||
let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations)
|
||||
self.insertSubnode(spoilerNode, aboveSubnode: self.imageNode)
|
||||
|
@ -384,6 +384,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1759532989] = { return Api.InputMedia.parse_inputMediaGeoLive($0) }
|
||||
dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) }
|
||||
dict[1080028941] = { return Api.InputMedia.parse_inputMediaInvoice($0) }
|
||||
dict[-1436147773] = { return Api.InputMedia.parse_inputMediaPaidMedia($0) }
|
||||
dict[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
|
||||
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
|
||||
dict[261416433] = { return Api.InputMedia.parse_inputMediaPoll($0) }
|
||||
@ -599,6 +600,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-626162256] = { return Api.MessageMedia.parse_messageMediaGiveaway($0) }
|
||||
dict[-963047320] = { return Api.MessageMedia.parse_messageMediaGiveawayResults($0) }
|
||||
dict[-156940077] = { return Api.MessageMedia.parse_messageMediaInvoice($0) }
|
||||
dict[-1467669359] = { return Api.MessageMedia.parse_messageMediaPaidMedia($0) }
|
||||
dict[1766936791] = { return Api.MessageMedia.parse_messageMediaPhoto($0) }
|
||||
dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
|
||||
dict[1758159491] = { return Api.MessageMedia.parse_messageMediaStory($0) }
|
||||
@ -874,7 +876,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
|
||||
dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($0) }
|
||||
dict[-1442789224] = { return Api.StarsTransaction.parse_starsTransaction($0) }
|
||||
dict[-901959922] = { return Api.StarsTransaction.parse_starsTransaction($0) }
|
||||
dict[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) }
|
||||
dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) }
|
||||
dict[-382740222] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerFragment($0) }
|
||||
@ -995,7 +997,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1442983757] = { return Api.Update.parse_updateLangPack($0) }
|
||||
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
|
||||
dict[1448076945] = { return Api.Update.parse_updateLoginToken($0) }
|
||||
dict[1517529484] = { return Api.Update.parse_updateMessageExtendedMedia($0) }
|
||||
dict[-710666460] = { return Api.Update.parse_updateMessageExtendedMedia($0) }
|
||||
dict[1318109142] = { return Api.Update.parse_updateMessageID($0) }
|
||||
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
||||
dict[619974263] = { return Api.Update.parse_updateMessagePollVote($0) }
|
||||
|
@ -9,6 +9,7 @@ public extension Api {
|
||||
case inputMediaGeoLive(flags: Int32, geoPoint: Api.InputGeoPoint, heading: Int32?, period: Int32?, proximityNotificationRadius: Int32?)
|
||||
case inputMediaGeoPoint(geoPoint: Api.InputGeoPoint)
|
||||
case inputMediaInvoice(flags: Int32, title: String, description: String, photo: Api.InputWebDocument?, invoice: Api.Invoice, payload: Buffer, provider: String?, providerData: Api.DataJSON, startParam: String?, extendedMedia: Api.InputMedia?)
|
||||
case inputMediaPaidMedia(starsAmount: Int64, extendedMedia: [Api.InputMedia])
|
||||
case inputMediaPhoto(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?)
|
||||
case inputMediaPhotoExternal(flags: Int32, url: String, ttlSeconds: Int32?)
|
||||
case inputMediaPoll(flags: Int32, poll: Api.Poll, correctAnswers: [Buffer]?, solution: String?, solutionEntities: [Api.MessageEntity]?)
|
||||
@ -95,6 +96,17 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {extendedMedia!.serialize(buffer, true)}
|
||||
break
|
||||
case .inputMediaPaidMedia(let starsAmount, let extendedMedia):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1436147773)
|
||||
}
|
||||
serializeInt64(starsAmount, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(extendedMedia.count))
|
||||
for item in extendedMedia {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1279654347)
|
||||
@ -210,6 +222,8 @@ public extension Api {
|
||||
return ("inputMediaGeoPoint", [("geoPoint", geoPoint as Any)])
|
||||
case .inputMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam, let extendedMedia):
|
||||
return ("inputMediaInvoice", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("invoice", invoice as Any), ("payload", payload as Any), ("provider", provider as Any), ("providerData", providerData as Any), ("startParam", startParam as Any), ("extendedMedia", extendedMedia as Any)])
|
||||
case .inputMediaPaidMedia(let starsAmount, let extendedMedia):
|
||||
return ("inputMediaPaidMedia", [("starsAmount", starsAmount as Any), ("extendedMedia", extendedMedia as Any)])
|
||||
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
|
||||
return ("inputMediaPhoto", [("flags", flags as Any), ("id", id as Any), ("ttlSeconds", ttlSeconds as Any)])
|
||||
case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds):
|
||||
@ -399,6 +413,22 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputMediaPaidMedia(_ reader: BufferReader) -> InputMedia? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: [Api.InputMedia]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputMedia.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.InputMedia.inputMediaPaidMedia(starsAmount: _1!, extendedMedia: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputMediaPhoto(_ reader: BufferReader) -> InputMedia? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
@ -718,6 +718,7 @@ public extension Api {
|
||||
case messageMediaGiveaway(flags: Int32, channels: [Int64], countriesIso2: [String]?, prizeDescription: String?, quantity: Int32, months: Int32, untilDate: Int32)
|
||||
case messageMediaGiveawayResults(flags: Int32, channelId: Int64, additionalPeersCount: Int32?, launchMsgId: Int32, winnersCount: Int32, unclaimedCount: Int32, winners: [Int64], months: Int32, prizeDescription: String?, untilDate: Int32)
|
||||
case messageMediaInvoice(flags: Int32, title: String, description: String, photo: Api.WebDocument?, receiptMsgId: Int32?, currency: String, totalAmount: Int64, startParam: String, extendedMedia: Api.MessageExtendedMedia?)
|
||||
case messageMediaPaidMedia(starsAmount: Int64, extendedMedia: [Api.MessageExtendedMedia])
|
||||
case messageMediaPhoto(flags: Int32, photo: Api.Photo?, ttlSeconds: Int32?)
|
||||
case messageMediaPoll(poll: Api.Poll, results: Api.PollResults)
|
||||
case messageMediaStory(flags: Int32, peer: Api.Peer, id: Int32, story: Api.StoryItem?)
|
||||
@ -834,6 +835,17 @@ public extension Api {
|
||||
serializeString(startParam, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 4) != 0 {extendedMedia!.serialize(buffer, true)}
|
||||
break
|
||||
case .messageMediaPaidMedia(let starsAmount, let extendedMedia):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1467669359)
|
||||
}
|
||||
serializeInt64(starsAmount, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(extendedMedia.count))
|
||||
for item in extendedMedia {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .messageMediaPhoto(let flags, let photo, let ttlSeconds):
|
||||
if boxed {
|
||||
buffer.appendInt32(1766936791)
|
||||
@ -907,6 +919,8 @@ public extension Api {
|
||||
return ("messageMediaGiveawayResults", [("flags", flags as Any), ("channelId", channelId as Any), ("additionalPeersCount", additionalPeersCount as Any), ("launchMsgId", launchMsgId as Any), ("winnersCount", winnersCount as Any), ("unclaimedCount", unclaimedCount as Any), ("winners", winners as Any), ("months", months as Any), ("prizeDescription", prizeDescription as Any), ("untilDate", untilDate as Any)])
|
||||
case .messageMediaInvoice(let flags, let title, let description, let photo, let receiptMsgId, let currency, let totalAmount, let startParam, let extendedMedia):
|
||||
return ("messageMediaInvoice", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("receiptMsgId", receiptMsgId as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("startParam", startParam as Any), ("extendedMedia", extendedMedia as Any)])
|
||||
case .messageMediaPaidMedia(let starsAmount, let extendedMedia):
|
||||
return ("messageMediaPaidMedia", [("starsAmount", starsAmount as Any), ("extendedMedia", extendedMedia as Any)])
|
||||
case .messageMediaPhoto(let flags, let photo, let ttlSeconds):
|
||||
return ("messageMediaPhoto", [("flags", flags as Any), ("photo", photo as Any), ("ttlSeconds", ttlSeconds as Any)])
|
||||
case .messageMediaPoll(let poll, let results):
|
||||
@ -1149,6 +1163,22 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageMediaPaidMedia(_ reader: BufferReader) -> MessageMedia? {
|
||||
var _1: Int64?
|
||||
_1 = reader.readInt64()
|
||||
var _2: [Api.MessageExtendedMedia]?
|
||||
if let _ = reader.readInt32() {
|
||||
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageExtendedMedia.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
if _c1 && _c2 {
|
||||
return Api.MessageMedia.messageMediaPaidMedia(starsAmount: _1!, extendedMedia: _2!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_messageMediaPhoto(_ reader: BufferReader) -> MessageMedia? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
|
@ -708,13 +708,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum StarsTransaction: TypeConstructorDescription {
|
||||
case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?)
|
||||
case starsTransaction(flags: Int32, id: String, stars: Int64, date: Int32, peer: Api.StarsTransactionPeer, title: String?, description: String?, photo: Api.WebDocument?, transactionDate: Int32?, transactionUrl: String?, botPayload: Buffer?, msgId: Int32?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl):
|
||||
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1442789224)
|
||||
buffer.appendInt32(-901959922)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(id, buffer: buffer, boxed: false)
|
||||
@ -726,14 +726,16 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 2) != 0 {photo!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 5) != 0 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 5) != 0 {serializeString(transactionUrl!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeBytes(botPayload!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt32(msgId!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl):
|
||||
return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any)])
|
||||
case .starsTransaction(let flags, let id, let stars, let date, let peer, let title, let description, let photo, let transactionDate, let transactionUrl, let botPayload, let msgId):
|
||||
return ("starsTransaction", [("flags", flags as Any), ("id", id as Any), ("stars", stars as Any), ("date", date as Any), ("peer", peer as Any), ("title", title as Any), ("description", description as Any), ("photo", photo as Any), ("transactionDate", transactionDate as Any), ("transactionUrl", transactionUrl as Any), ("botPayload", botPayload as Any), ("msgId", msgId as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,6 +764,10 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 5) != 0 {_9 = reader.readInt32() }
|
||||
var _10: String?
|
||||
if Int(_1!) & Int(1 << 5) != 0 {_10 = parseString(reader) }
|
||||
var _11: Buffer?
|
||||
if Int(_1!) & Int(1 << 7) != 0 {_11 = parseBytes(reader) }
|
||||
var _12: Int32?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_12 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -772,8 +778,10 @@ public extension Api {
|
||||
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
||||
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10)
|
||||
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
|
||||
let _c12 = (Int(_1!) & Int(1 << 8) == 0) || _12 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 {
|
||||
return Api.StarsTransaction.starsTransaction(flags: _1!, id: _2!, stars: _3!, date: _4!, peer: _5!, title: _6, description: _7, photo: _8, transactionDate: _9, transactionUrl: _10, botPayload: _11, msgId: _12)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -321,7 +321,7 @@ public extension Api {
|
||||
case updateLangPack(difference: Api.LangPackDifference)
|
||||
case updateLangPackTooLong(langCode: String)
|
||||
case updateLoginToken
|
||||
case updateMessageExtendedMedia(peer: Api.Peer, msgId: Int32, extendedMedia: Api.MessageExtendedMedia)
|
||||
case updateMessageExtendedMedia(peer: Api.Peer, msgId: Int32, extendedMedia: [Api.MessageExtendedMedia])
|
||||
case updateMessageID(id: Int32, randomId: Int64)
|
||||
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
|
||||
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32)
|
||||
@ -1039,11 +1039,15 @@ public extension Api {
|
||||
break
|
||||
case .updateMessageExtendedMedia(let peer, let msgId, let extendedMedia):
|
||||
if boxed {
|
||||
buffer.appendInt32(1517529484)
|
||||
buffer.appendInt32(-710666460)
|
||||
}
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
extendedMedia.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(extendedMedia.count))
|
||||
for item in extendedMedia {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
break
|
||||
case .updateMessageID(let id, let randomId):
|
||||
if boxed {
|
||||
@ -3241,9 +3245,9 @@ public extension Api {
|
||||
}
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Api.MessageExtendedMedia?
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.MessageExtendedMedia
|
||||
var _3: [Api.MessageExtendedMedia]?
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageExtendedMedia.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
|
@ -120,7 +120,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateAttachMenuBots
|
||||
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
||||
case UpdateConfig
|
||||
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
|
||||
case UpdateExtendedMedia(MessageId, [Api.MessageExtendedMedia])
|
||||
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
|
||||
case UpdateStory(peerId: PeerId, story: Api.StoryItem)
|
||||
case UpdateReadStories(peerId: PeerId, maxId: Int32)
|
||||
@ -652,7 +652,7 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateConfig)
|
||||
}
|
||||
|
||||
mutating func updateExtendedMedia(_ messageId: MessageId, extendedMedia: Api.MessageExtendedMedia) {
|
||||
mutating func updateExtendedMedia(_ messageId: MessageId, extendedMedia: [Api.MessageExtendedMedia]) {
|
||||
self.addOperation(.UpdateExtendedMedia(messageId, extendedMedia))
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(OutgoingQuickReplyMessageAttribute.self, f: { OutgoingQuickReplyMessageAttribute(decoder: $0) })
|
||||
declareEncodable(EffectMessageAttribute.self, f: { EffectMessageAttribute(decoder: $0) })
|
||||
declareEncodable(FactCheckMessageAttribute.self, f: { FactCheckMessageAttribute(decoder: $0) })
|
||||
declareEncodable(TelegramMediaPaidContent.self, f: { TelegramMediaPaidContent(decoder: $0) })
|
||||
return
|
||||
}()
|
||||
|
||||
|
@ -391,33 +391,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
parsedFlags.insert(.shippingAddressRequested)
|
||||
}
|
||||
|
||||
let extendedMedia: TelegramExtendedMedia?
|
||||
if let apiExtendedMedia = apiExtendedMedia {
|
||||
switch apiExtendedMedia {
|
||||
case let .messageExtendedMediaPreview(_, width, height, thumb, videoDuration):
|
||||
var dimensions: PixelDimensions?
|
||||
if let width = width, let height = height {
|
||||
dimensions = PixelDimensions(width: width, height: height)
|
||||
}
|
||||
var immediateThumbnailData: Data?
|
||||
if let thumb = thumb, case let .photoStrippedSize(_, bytes) = thumb {
|
||||
immediateThumbnailData = bytes.makeData()
|
||||
}
|
||||
extendedMedia = .preview(dimensions: dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: videoDuration)
|
||||
case let .messageExtendedMedia(apiMedia):
|
||||
let (media, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, peerId)
|
||||
if let media = media {
|
||||
extendedMedia = .full(media: media)
|
||||
} else {
|
||||
extendedMedia = nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
extendedMedia = nil
|
||||
}
|
||||
|
||||
return (TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: receiptMsgId.flatMap { MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }, currency: currency, totalAmount: totalAmount, startParam: startParam, extendedMedia: extendedMedia, flags: parsedFlags, version: TelegramMediaInvoice.lastVersion), nil, nil, nil, nil)
|
||||
return (TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: receiptMsgId.flatMap { MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: $0) }, currency: currency, totalAmount: totalAmount, startParam: startParam, extendedMedia: apiExtendedMedia.flatMap({ TelegramExtendedMedia(apiExtendedMedia: $0, peerId: peerId) }), flags: parsedFlags, version: TelegramMediaInvoice.lastVersion), nil, nil, nil, nil)
|
||||
case let .messageMediaPoll(poll, results):
|
||||
switch poll {
|
||||
case let .poll(id, flags, question, answers, closePeriod, _):
|
||||
@ -464,6 +438,8 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
||||
flags.insert(.refunded)
|
||||
}
|
||||
return (TelegramMediaGiveawayResults(flags: flags, launchMessageId: MessageId(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: launchMsgId), additionalChannelsCount: additionalPeersCount ?? 0, winnersPeerIds: winners.map { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }, winnersCount: winnersCount, unclaimedCount: unclaimedCount, months: months, untilDate: untilDate, prizeDescription: prizeDescription), nil, nil, nil, nil)
|
||||
case let .messageMediaPaidMedia(starsAmount, apiExtendedMedia):
|
||||
return (TelegramMediaPaidContent(amount: starsAmount, extendedMedia: apiExtendedMedia.compactMap({ TelegramExtendedMedia(apiExtendedMedia: $0, peerId: peerId) })), nil, nil, nil, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
|
||||
extension TelegramExtendedMedia {
|
||||
init?(apiExtendedMedia: Api.MessageExtendedMedia, peerId: PeerId) {
|
||||
switch apiExtendedMedia {
|
||||
case let .messageExtendedMediaPreview(_, width, height, thumb, videoDuration):
|
||||
var dimensions: PixelDimensions?
|
||||
if let width = width, let height = height {
|
||||
dimensions = PixelDimensions(width: width, height: height)
|
||||
}
|
||||
var immediateThumbnailData: Data?
|
||||
if let thumb = thumb, case let .photoStrippedSize(_, bytes) = thumb {
|
||||
immediateThumbnailData = bytes.makeData()
|
||||
}
|
||||
self = .preview(dimensions: dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: videoDuration)
|
||||
case let .messageExtendedMedia(apiMedia):
|
||||
let (media, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, peerId)
|
||||
if let media = media {
|
||||
self = .full(media: media)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -119,6 +119,44 @@ func messageContentToUpload(accountPeerId: PeerId, network: Network, postbox: Po
|
||||
}
|
||||
|
||||
func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, passFetchProgress: Bool, forceNoBigParts: Bool, peerId: PeerId, media: Media, text: String, autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute], mediaReference: AnyMediaReference?) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>? {
|
||||
if let paidContent = media as? TelegramMediaPaidContent {
|
||||
var signals: [Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>] = []
|
||||
for case let .full(media) in paidContent.extendedMedia {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
signals.append(uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, forceReupload: forceReupload, isGrouped: false, peerId: peerId, image: image, messageId: messageId, text: "", attributes: [], autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, auxiliaryMethods: auxiliaryMethods))
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
signals.append(uploadedMediaFileContent(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: false, passFetchProgress: false, forceNoBigParts: false, peerId: peerId, messageId: messageId, text: "", attributes: [], autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, file: file))
|
||||
}
|
||||
}
|
||||
return combineLatest(signals)
|
||||
|> map { results -> PendingMessageUploadedContentResult in
|
||||
var currentProgress: Float = 0.0
|
||||
var media: [Api.InputMedia] = []
|
||||
for result in results {
|
||||
switch result {
|
||||
case let .progress(progress):
|
||||
currentProgress += progress
|
||||
case let .content(content):
|
||||
if case let .media(resultMedia, _) = content.content {
|
||||
media.append(resultMedia)
|
||||
}
|
||||
}
|
||||
}
|
||||
let normalizedProgress = currentProgress / Float(results.count)
|
||||
if media.count == results.count {
|
||||
return .content(PendingMessageUploadedContentAndReuploadInfo(
|
||||
content: .media(.inputMediaPaidMedia(
|
||||
starsAmount: paidContent.amount,
|
||||
extendedMedia: media
|
||||
), text),
|
||||
reuploadInfo: nil,
|
||||
cacheReferenceKey: nil
|
||||
))
|
||||
} else {
|
||||
return .progress(normalizedProgress)
|
||||
}
|
||||
}
|
||||
}
|
||||
if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) {
|
||||
if peerId.namespace == Namespaces.Peer.SecretChat, let resource = largest.resource as? SecretFileMediaResource {
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(.inputEncryptedFile(id: resource.fileId, accessHash: resource.accessHash), resource.decryptedSize, resource.key), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||
|
@ -4633,42 +4633,26 @@ func replayFinalState(
|
||||
transaction.updateMessage(messageId, update: { currentMessage in
|
||||
var media = currentMessage.media
|
||||
let invoice = media.first(where: { $0 is TelegramMediaInvoice }) as? TelegramMediaInvoice
|
||||
let currentExtendedMedia = invoice?.extendedMedia
|
||||
let paidContent = media.first(where: { $0 is TelegramMediaPaidContent }) as? TelegramMediaPaidContent
|
||||
|
||||
var storeForwardInfo: StoreMessageForwardInfo?
|
||||
if let forwardInfo = currentMessage.forwardInfo {
|
||||
storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags)
|
||||
}
|
||||
|
||||
let updatedExtendedMedia: TelegramExtendedMedia?
|
||||
switch apiExtendedMedia {
|
||||
case let .messageExtendedMediaPreview(_, width, height, thumb, videoDuration):
|
||||
var dimensions: PixelDimensions?
|
||||
if let width = width, let height = height {
|
||||
dimensions = PixelDimensions(width: width, height: height)
|
||||
}
|
||||
var immediateThumbnailData: Data?
|
||||
if let thumb = thumb, case let .photoStrippedSize(_, bytes) = thumb {
|
||||
immediateThumbnailData = bytes.makeData()
|
||||
}
|
||||
updatedExtendedMedia = .preview(dimensions: dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: videoDuration)
|
||||
case let .messageExtendedMedia(apiMedia):
|
||||
let (media, _, _, _, _) = textMediaAndExpirationTimerFromApiMedia(apiMedia, currentMessage.id.peerId)
|
||||
if let media = media {
|
||||
updatedExtendedMedia = .full(media: media)
|
||||
} else {
|
||||
updatedExtendedMedia = currentExtendedMedia
|
||||
}
|
||||
}
|
||||
let updatedExtendedMedia = apiExtendedMedia.compactMap { TelegramExtendedMedia(apiExtendedMedia: $0, peerId: messageId.peerId) }
|
||||
|
||||
if let updatedExtendedMedia = updatedExtendedMedia, var invoice = invoice {
|
||||
if let currentExtendedMedia = currentExtendedMedia, case .full = currentExtendedMedia, case .preview = updatedExtendedMedia {
|
||||
|
||||
} else {
|
||||
if let first = updatedExtendedMedia.first, case .full = first {
|
||||
if var invoice = invoice {
|
||||
media = media.filter { !($0 is TelegramMediaInvoice) }
|
||||
invoice = invoice.withUpdatedExtendedMedia(updatedExtendedMedia)
|
||||
invoice = invoice.withUpdatedExtendedMedia(first)
|
||||
media.append(invoice)
|
||||
}
|
||||
if var paidContent = paidContent {
|
||||
media = media.filter { !($0 is TelegramMediaPaidContent) }
|
||||
paidContent = paidContent.withUpdatedExtendedMedia(updatedExtendedMedia)
|
||||
media.append(paidContent)
|
||||
}
|
||||
}
|
||||
|
||||
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: currentMessage.attributes, media: media))
|
||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 182
|
||||
return 183
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -0,0 +1,59 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
public final class TelegramMediaPaidContent: Media, Equatable {
|
||||
public var peerIds: [PeerId] = []
|
||||
|
||||
public var id: MediaId? {
|
||||
return nil
|
||||
}
|
||||
|
||||
public let amount: Int64
|
||||
public let extendedMedia: [TelegramExtendedMedia]
|
||||
|
||||
public init(amount: Int64, extendedMedia: [TelegramExtendedMedia]) {
|
||||
self.amount = amount
|
||||
self.extendedMedia = extendedMedia
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.amount = decoder.decodeInt64ForKey("a", orElse: 0)
|
||||
self.extendedMedia = (try? decoder.decodeObjectArrayWithCustomDecoderForKey("m", decoder: { TelegramExtendedMedia(decoder: $0) })) ?? []
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt64(self.amount, forKey: "a")
|
||||
encoder.encodeObjectArray(self.extendedMedia, forKey: "m")
|
||||
}
|
||||
|
||||
public static func ==(lhs: TelegramMediaPaidContent, rhs: TelegramMediaPaidContent) -> Bool {
|
||||
return lhs.isEqual(to: rhs)
|
||||
}
|
||||
|
||||
public func isEqual(to other: Media) -> Bool {
|
||||
guard let other = other as? TelegramMediaPaidContent else {
|
||||
return false
|
||||
}
|
||||
|
||||
if self.amount != other.amount {
|
||||
return false
|
||||
}
|
||||
|
||||
if self.extendedMedia != other.extendedMedia {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
public func isSemanticallyEqual(to other: Media) -> Bool {
|
||||
return self.isEqual(to: other)
|
||||
}
|
||||
|
||||
public func withUpdatedExtendedMedia(_ extendedMedia: [TelegramExtendedMedia]) -> TelegramMediaPaidContent {
|
||||
return TelegramMediaPaidContent(
|
||||
amount: self.amount,
|
||||
extendedMedia: extendedMedia
|
||||
)
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ public enum EngineMedia: Equatable {
|
||||
case story(TelegramMediaStory)
|
||||
case giveaway(TelegramMediaGiveaway)
|
||||
case giveawayResults(TelegramMediaGiveawayResults)
|
||||
case paidContent(TelegramMediaPaidContent)
|
||||
}
|
||||
|
||||
public extension EngineMedia {
|
||||
@ -56,6 +57,8 @@ public extension EngineMedia {
|
||||
return giveaway.id
|
||||
case let .giveawayResults(giveawayResults):
|
||||
return giveawayResults.id
|
||||
case let .paidContent(paidContent):
|
||||
return paidContent.id
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -95,6 +98,8 @@ public extension EngineMedia {
|
||||
self = .giveaway(giveaway)
|
||||
case let giveawayResults as TelegramMediaGiveawayResults:
|
||||
self = .giveawayResults(giveawayResults)
|
||||
case let paidContent as TelegramMediaPaidContent:
|
||||
self = .paidContent(paidContent)
|
||||
default:
|
||||
preconditionFailure()
|
||||
}
|
||||
@ -134,6 +139,8 @@ public extension EngineMedia {
|
||||
return giveaway
|
||||
case let .giveawayResults(giveawayResults):
|
||||
return giveawayResults
|
||||
case let .paidContent(paidContent):
|
||||
return paidContent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ private final class StarsContextImpl {
|
||||
return
|
||||
}
|
||||
var transactions = state.transactions
|
||||
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil), at: 0)
|
||||
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil), at: 0)
|
||||
|
||||
self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: state.balance + balance, transactions: transactions, canLoadMore: state.canLoadMore, isLoading: state.isLoading))
|
||||
}
|
||||
@ -238,8 +238,9 @@ private final class StarsContextImpl {
|
||||
private extension StarsContext.State.Transaction {
|
||||
init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) {
|
||||
switch apiTransaction {
|
||||
case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl):
|
||||
case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId):
|
||||
let parsedPeer: StarsContext.State.Transaction.Peer
|
||||
var paidMessageId: MessageId?
|
||||
switch transactionPeer {
|
||||
case .starsTransactionPeerAppStore:
|
||||
parsedPeer = .appStore
|
||||
@ -256,13 +257,19 @@ private extension StarsContext.State.Transaction {
|
||||
return nil
|
||||
}
|
||||
parsedPeer = .peer(EnginePeer(peer))
|
||||
if let messageId {
|
||||
paidMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||
}
|
||||
}
|
||||
|
||||
var flags: Flags = []
|
||||
if (apiFlags & (1 << 3)) != 0 {
|
||||
flags.insert(.isRefund)
|
||||
}
|
||||
self.init(flags: flags, id: id, count: stars, date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl)
|
||||
if (apiFlags & (1 << 6)) != 0 {
|
||||
flags.insert(.isFailed)
|
||||
}
|
||||
self.init(flags: flags, id: id, count: stars, date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -280,6 +287,7 @@ public final class StarsContext {
|
||||
public static let isRefund = Flags(rawValue: 1 << 0)
|
||||
public static let isLocal = Flags(rawValue: 1 << 1)
|
||||
public static let isPending = Flags(rawValue: 1 << 2)
|
||||
public static let isFailed = Flags(rawValue: 1 << 3)
|
||||
}
|
||||
|
||||
public enum Peer: Equatable {
|
||||
@ -301,6 +309,7 @@ public final class StarsContext {
|
||||
public let photo: TelegramMediaWebFile?
|
||||
public let transactionDate: Int32?
|
||||
public let transactionUrl: String?
|
||||
public let paidMessageId: MessageId?
|
||||
|
||||
public init(
|
||||
flags: Flags,
|
||||
@ -312,7 +321,8 @@ public final class StarsContext {
|
||||
description: String?,
|
||||
photo: TelegramMediaWebFile?,
|
||||
transactionDate: Int32?,
|
||||
transactionUrl: String?
|
||||
transactionUrl: String?,
|
||||
paidMessageId: MessageId?
|
||||
) {
|
||||
self.flags = flags
|
||||
self.id = id
|
||||
@ -324,6 +334,7 @@ public final class StarsContext {
|
||||
self.photo = photo
|
||||
self.transactionDate = transactionDate
|
||||
self.transactionUrl = transactionUrl
|
||||
self.paidMessageId = paidMessageId
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ public enum MessageContentKindKey {
|
||||
case invoice
|
||||
case story
|
||||
case giveaway
|
||||
case paidContent
|
||||
}
|
||||
|
||||
public enum MessageContentKind: Equatable {
|
||||
@ -54,6 +55,7 @@ public enum MessageContentKind: Equatable {
|
||||
case invoice(String)
|
||||
case story
|
||||
case giveaway
|
||||
case paidContent
|
||||
|
||||
public func isSemanticallyEqual(to other: MessageContentKind) -> Bool {
|
||||
switch self {
|
||||
@ -189,6 +191,12 @@ public enum MessageContentKind: Equatable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .paidContent:
|
||||
if case .paidContent = other {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +246,8 @@ public enum MessageContentKind: Equatable {
|
||||
return .story
|
||||
case .giveaway:
|
||||
return .giveaway
|
||||
case .paidContent:
|
||||
return .paidContent
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,6 +455,8 @@ public func stringForMediaKind(_ kind: MessageContentKind, strings: Presentation
|
||||
return (NSAttributedString(string: strings.Message_Story), true)
|
||||
case .giveaway:
|
||||
return (NSAttributedString(string: strings.Message_Giveaway), true)
|
||||
case .paidContent:
|
||||
return (NSAttributedString(string: "Paid Media"), true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -406,6 +406,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
attributes,
|
||||
contentMediaValue,
|
||||
nil,
|
||||
nil,
|
||||
.full,
|
||||
associatedData.automaticDownloadPeerType,
|
||||
associatedData.automaticDownloadPeerId,
|
||||
|
@ -118,7 +118,7 @@ public enum ChatMessageBubbleContentPosition {
|
||||
|
||||
public enum ChatMessageBubblePreparePosition {
|
||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition, index: Int?)
|
||||
}
|
||||
|
||||
public struct ChatMessageBubbleContentTapAction {
|
||||
@ -208,6 +208,8 @@ open class ChatMessageBubbleContentNode: ASDisplayNode {
|
||||
return false
|
||||
}
|
||||
|
||||
open var index: Int?
|
||||
|
||||
public weak var itemNode: ChatMessageItemNodeProtocol?
|
||||
public weak var bubbleBackgroundNode: ChatMessageBackground?
|
||||
public weak var bubbleBackdropNode: ChatMessageBubbleBackdrop?
|
||||
|
@ -78,9 +78,17 @@ import TelegramAnimatedStickerNode
|
||||
import LottieMetal
|
||||
|
||||
private struct BubbleItemAttributes {
|
||||
var index: Int?
|
||||
var isAttachment: Bool
|
||||
var neighborType: ChatMessageBubbleRelativePosition.NeighbourType
|
||||
var neighborSpacing: ChatMessageBubbleRelativePosition.NeighbourSpacing
|
||||
|
||||
init(index: Int? = nil, isAttachment: Bool, neighborType: ChatMessageBubbleRelativePosition.NeighbourType, neighborSpacing: ChatMessageBubbleRelativePosition.NeighbourSpacing) {
|
||||
self.index = index
|
||||
self.isAttachment = isAttachment
|
||||
self.neighborType = neighborType
|
||||
self.neighborSpacing = neighborSpacing
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChatMessageBubbleClippingNode: ASDisplayNode {
|
||||
@ -123,7 +131,13 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
||||
|
||||
var isFile = false
|
||||
inner: for media in message.media {
|
||||
if let _ = media as? TelegramMediaImage {
|
||||
if let media = media as? TelegramMediaPaidContent {
|
||||
var index = 0
|
||||
for _ in media.extendedMedia {
|
||||
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(index: index, isAttachment: true, neighborType: .media, neighborSpacing: .default)))
|
||||
index += 1
|
||||
}
|
||||
} else if let _ = media as? TelegramMediaImage {
|
||||
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), message.text.isEmpty {
|
||||
messageWithCaptionToAdd = (message, itemAttributes)
|
||||
}
|
||||
@ -1334,10 +1348,10 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
|
||||
override public func asyncLayout() -> (_ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, ListViewItemApply, Bool) -> Void) {
|
||||
var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = []
|
||||
var currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, Int?, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = []
|
||||
for contentNode in self.contentNodes {
|
||||
if let message = contentNode.item?.message {
|
||||
currentContentClassesPropertiesAndLayouts.append((message, type(of: contentNode) as AnyClass, contentNode.supportsMosaic, contentNode.asyncLayoutContent()))
|
||||
currentContentClassesPropertiesAndLayouts.append((message, type(of: contentNode) as AnyClass, contentNode.supportsMosaic, contentNode.index, contentNode.asyncLayoutContent()))
|
||||
} else {
|
||||
assertionFailure()
|
||||
}
|
||||
@ -1388,7 +1402,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
|
||||
private static func beginLayout(
|
||||
selfReference: Weak<ChatMessageBubbleItemNode>, _ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool,
|
||||
currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))],
|
||||
currentContentClassesPropertiesAndLayouts: [(Message, AnyClass, Bool, Int?, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))],
|
||||
authorNameLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||
viaMeasureLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||
adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||
@ -1699,15 +1713,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
maximumContentWidth = max(0.0, maximumContentWidth)
|
||||
|
||||
var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, BubbleItemAttributes, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))] = []
|
||||
var addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]?
|
||||
var addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode, Int?)]?
|
||||
for contentNodeItemValue in contentNodeMessagesAndClasses {
|
||||
let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes)
|
||||
|
||||
var found = false
|
||||
for currentNodeItemValue in currentContentClassesPropertiesAndLayouts {
|
||||
let currentNodeItem = currentNodeItemValue as (message: Message, type: AnyClass, supportsMosaic: Bool, currentLayout: (ChatMessageBubbleContentItem, ChatMessageItemLayoutConstants, ChatMessageBubblePreparePosition, Bool?, CGSize, CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))
|
||||
let currentNodeItem = currentNodeItemValue as (message: Message, type: AnyClass, supportsMosaic: Bool, index: Int?, currentLayout: (ChatMessageBubbleContentItem, ChatMessageItemLayoutConstants, ChatMessageBubblePreparePosition, Bool?, CGSize, CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))))
|
||||
|
||||
if currentNodeItem.type == contentNodeItem.type && currentNodeItem.message.stableId == contentNodeItem.message.stableId {
|
||||
if currentNodeItem.type == contentNodeItem.type && currentNodeItem.index == contentNodeItem.bubbleAttributes.index && currentNodeItem.message.stableId == contentNodeItem.message.stableId {
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, currentNodeItem.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, currentNodeItem.currentLayout))
|
||||
found = true
|
||||
break
|
||||
@ -1715,11 +1729,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
if !found {
|
||||
let contentNode = (contentNodeItem.type as! ChatMessageBubbleContentNode.Type).init()
|
||||
contentNode.index = contentNodeItem.bubbleAttributes.index
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, contentNode.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, contentNode.asyncLayoutContent()))
|
||||
if addedContentNodes == nil {
|
||||
addedContentNodes = []
|
||||
}
|
||||
addedContentNodes!.append((contentNodeItem.message, contentNodeItem.bubbleAttributes.isAttachment, contentNode))
|
||||
addedContentNodes!.append((contentNodeItem.message, contentNodeItem.bubbleAttributes.isAttachment, contentNode, contentNodeItem.bubbleAttributes.index))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1924,7 +1939,8 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
|
||||
let prepareContentPosition: ChatMessageBubblePreparePosition
|
||||
if let mosaicRange = mosaicRange, mosaicRange.contains(index) {
|
||||
prepareContentPosition = .mosaic(top: .None(.None(.Incoming)), bottom: index == (mosaicRange.upperBound - 1) ? bottomPosition : .None(.None(.Incoming)))
|
||||
let mosaicIndex = index - mosaicRange.lowerBound
|
||||
prepareContentPosition = .mosaic(top: .None(.None(.Incoming)), bottom: index == (mosaicRange.upperBound - 1) ? bottomPosition : .None(.None(.Incoming)), index: mosaicIndex)
|
||||
} else {
|
||||
let refinedBottomPosition: ChatMessageBubbleRelativePosition
|
||||
if index == contentPropertiesAndPrepareLayouts.count - 1 {
|
||||
@ -3071,7 +3087,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
replyInfoOriginY: CGFloat,
|
||||
removedContentNodeIndices: [Int]?,
|
||||
updatedContentNodeOrder: Bool,
|
||||
addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]?,
|
||||
addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode, Int?)]?,
|
||||
contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)],
|
||||
contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, Bool, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)],
|
||||
contentContainerNodeFrames: [(UInt32, CGRect, Bool?, CGFloat)],
|
||||
@ -3876,7 +3892,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
|
||||
if let addedContentNodes = addedContentNodes {
|
||||
for (contentNodeMessage, isAttachment, contentNode) in addedContentNodes {
|
||||
for (contentNodeMessage, isAttachment, contentNode, _ ) in addedContentNodes {
|
||||
updatedContentNodes.append(contentNode)
|
||||
|
||||
let contextSourceNode: ContextExtractedContentContainingNode
|
||||
@ -3908,18 +3924,17 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
|
||||
var sortedContentNodes: [ChatMessageBubbleContentNode] = []
|
||||
outer: for contentItemValue in contentNodeMessagesAndClasses {
|
||||
let contentItem = contentItemValue as (message: Message, type: AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)
|
||||
|
||||
let contentItem = contentItemValue as (message: Message, type: AnyClass, ChatMessageEntryAttributes, attributes: BubbleItemAttributes)
|
||||
if let addedContentNodes = addedContentNodes {
|
||||
for (contentNodeMessage, _, contentNode) in addedContentNodes {
|
||||
if type(of: contentNode) == contentItem.type && contentNodeMessage.stableId == contentItem.message.stableId {
|
||||
for (contentNodeMessage, _, contentNode, index) in addedContentNodes {
|
||||
if type(of: contentNode) == contentItem.type && index == contentItem.attributes.index && contentNodeMessage.stableId == contentItem.message.stableId {
|
||||
sortedContentNodes.append(contentNode)
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
for contentNode in updatedContentNodes {
|
||||
if type(of: contentNode) == contentItem.type && contentNode.item?.message.stableId == contentItem.message.stableId {
|
||||
if type(of: contentNode) == contentItem.type && contentNode.index == contentItem.attributes.index && contentNode.item?.message.stableId == contentItem.message.stableId {
|
||||
sortedContentNodes.append(contentNode)
|
||||
continue outer
|
||||
}
|
||||
|
@ -437,6 +437,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
private var message: Message?
|
||||
private var attributes: ChatMessageEntryAttributes?
|
||||
private var media: Media?
|
||||
private var mediaIndex: Int?
|
||||
private var themeAndStrings: (PresentationTheme, PresentationStrings, String, Bool)?
|
||||
private var sizeCalculation: InteractiveMediaNodeSizeCalculation?
|
||||
private var wideLayout: Bool?
|
||||
@ -719,6 +720,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
} else {
|
||||
if let invoice = self.media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||
self.activateLocalContent(.default)
|
||||
} else if let _ = self.media as? TelegramMediaPaidContent {
|
||||
self.activateLocalContent(.default)
|
||||
} else if let storyMedia = media as? TelegramMediaStory, let storyItem = self.message?.associatedStories[storyMedia.storyId]?.get(Stories.StoredItem.self) {
|
||||
if case let .item(item) = storyItem, let mediaValue = item.media {
|
||||
let _ = mediaValue
|
||||
@ -732,7 +735,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
}
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
|
||||
public func asyncLayout() -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ mediaIndex: Int?, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
|
||||
let currentMessage = self.message
|
||||
let currentMedia = self.media
|
||||
let imageLayout = self.imageNode.asyncLayout()
|
||||
@ -746,7 +749,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
let currentAutomaticDownload = self.automaticDownload
|
||||
let currentAutomaticPlayback = self.automaticPlayback
|
||||
|
||||
return { [weak self] context, presentationData, dateTimeFormat, message, associatedData, attributes, media, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext in
|
||||
return { [weak self] context, presentationData, dateTimeFormat, message, associatedData, attributes, media, mediaIndex, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext in
|
||||
let _ = peerType
|
||||
|
||||
var nativeSize: CGSize
|
||||
@ -845,8 +848,18 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
case .color, .gradient, .emoticon:
|
||||
unboundSize = CGSize(width: 128.0, height: 128.0)
|
||||
}
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||
switch extendedMedia {
|
||||
} else {
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
let selectedMediaIndex = mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
if let extendedMedia {
|
||||
switch extendedMedia {
|
||||
case let .preview(dimensions, _, _):
|
||||
if let dimensions = dimensions {
|
||||
unboundSize = CGSize(width: max(10.0, floor(dimensions.cgSize.width * 0.5)), height: max(10.0, floor(dimensions.cgSize.height * 0.5)))
|
||||
@ -880,9 +893,10 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
} else {
|
||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
||||
}
|
||||
} else {
|
||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
||||
}
|
||||
|
||||
switch sizeCalculation {
|
||||
@ -1090,7 +1104,18 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
|
||||
if mediaUpdated || isSendingUpdated || automaticPlaybackUpdated {
|
||||
var media = media
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
let selectedMediaIndex = mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
|
||||
if let extendedMedia {
|
||||
switch extendedMedia {
|
||||
case let .preview(_, immediateThumbnailData, _):
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
@ -1418,7 +1443,16 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
var isExtendedMedia = false
|
||||
if statusUpdated {
|
||||
var media = media
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
let selectedMediaIndex = mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
if let extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
isExtendedMedia = true
|
||||
media = fullMedia
|
||||
}
|
||||
@ -1481,6 +1515,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
strongSelf.message = message
|
||||
strongSelf.attributes = attributes
|
||||
strongSelf.media = media
|
||||
strongSelf.mediaIndex = mediaIndex
|
||||
strongSelf.wideLayout = wideLayout
|
||||
strongSelf.themeAndStrings = (presentationData.theme.theme, presentationData.strings, dateTimeFormat.decimalSeparator, presentationData.isPreview)
|
||||
strongSelf.sizeCalculation = sizeCalculation
|
||||
@ -1719,7 +1754,16 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
let _ = strongSelf.fetchControls.swap(updatedFetchControls)
|
||||
|
||||
var media = media
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
let selectedMediaIndex = mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
if let extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
media = fullMedia
|
||||
}
|
||||
if let storyMedia = media as? TelegramMediaStory, let storyItem = message.associatedStories[storyMedia.storyId]?.get(Stories.StoredItem.self) {
|
||||
@ -1824,11 +1868,14 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
var game: TelegramMediaGame?
|
||||
var webpage: TelegramMediaWebpage?
|
||||
var invoice: TelegramMediaInvoice?
|
||||
var paidContent: TelegramMediaPaidContent?
|
||||
for media in message.media {
|
||||
if let media = media as? TelegramMediaWebpage {
|
||||
webpage = media
|
||||
} else if let media = media as? TelegramMediaInvoice {
|
||||
invoice = media
|
||||
} else if let media = media as? TelegramMediaPaidContent {
|
||||
paidContent = media
|
||||
} else if let media = media as? TelegramMediaGame {
|
||||
game = media
|
||||
} else if let _ = media as? TelegramMediaStory {
|
||||
@ -1836,9 +1883,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
automaticPlayback = false
|
||||
}
|
||||
}
|
||||
if let media = self.media as? TelegramMediaInvoice {
|
||||
invoice = media
|
||||
}
|
||||
|
||||
var progressRequired = false
|
||||
if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media {
|
||||
@ -1999,7 +2043,16 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator)
|
||||
|
||||
var media = self.media
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice = media as? TelegramMediaInvoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
let selectedMediaIndex = mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
if let extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
media = fullMedia
|
||||
}
|
||||
if let storyMedia = media as? TelegramMediaStory, let storyItem = message.associatedStories[storyMedia.storyId]?.get(Stories.StoredItem.self) {
|
||||
@ -2263,11 +2316,22 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
badgeNode.removeFromSupernode()
|
||||
}
|
||||
|
||||
var icon: ExtendedMediaOverlayNode.Icon? = .lock
|
||||
var icon: ExtendedMediaOverlayNode.Icon?
|
||||
var displaySpoiler = false
|
||||
if let invoice = invoice, let extendedMedia = invoice.extendedMedia, case .preview = extendedMedia {
|
||||
if invoice.currency == "XTR" {
|
||||
icon = nil
|
||||
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
if let invoice, let selectedMedia = invoice.extendedMedia {
|
||||
extendedMedia = selectedMedia
|
||||
} else if let paidContent {
|
||||
let selectedMediaIndex = self.mediaIndex ?? 0
|
||||
if selectedMediaIndex < paidContent.extendedMedia.count {
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
|
||||
if let extendedMedia, case .preview = extendedMedia {
|
||||
if let invoice, invoice.currency != "XTR" {
|
||||
icon = .lock
|
||||
}
|
||||
displaySpoiler = true
|
||||
} else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
|
||||
@ -2331,8 +2395,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
}
|
||||
}
|
||||
}
|
||||
if let invoice, invoice.currency == "XTR" && viewText.isEmpty {
|
||||
viewText = "Unlock for ⭐️\(invoice.totalAmount)"
|
||||
if let paidContent {
|
||||
viewText = "⭐️\(paidContent.amount)"
|
||||
}
|
||||
self.extendedMediaOverlayNode?.update(size: self.imageNode.frame.size, text: viewText, imageSignal: self.currentBlurredImageSignal, imageFrame: self.imageNode.view.convert(self.imageNode.bounds, to: self.extendedMediaOverlayNode?.view), corners: self.currentImageArguments?.corners)
|
||||
} else if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
||||
@ -2361,12 +2425,12 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
self.extendedMediaOverlayNode?.reveal(animated: true)
|
||||
}
|
||||
|
||||
public static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> ChatMessageInteractiveMediaNode))) {
|
||||
public static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ mediaIndex: Int?, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> ChatMessageInteractiveMediaNode))) {
|
||||
let currentAsyncLayout = node?.asyncLayout()
|
||||
|
||||
return { context, presentationData, dateTimeFormat, message, associatedData, attributes, media, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext in
|
||||
return { context, presentationData, dateTimeFormat, message, associatedData, attributes, media, mediaIndex, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext in
|
||||
var imageNode: ChatMessageInteractiveMediaNode
|
||||
var imageLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))
|
||||
var imageLayout: (_ context: AccountContext, _ presentationData: ChatPresentationData, _ dateTimeFormat: PresentationDateTimeFormat, _ message: Message, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ media: Media, _ mediaIndex: Int?, _ dateAndStatus: ChatMessageDateAndStatus?, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: MediaAutoDownloadPeerType, _ peerId: EnginePeer.Id?, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode, _ presentationContext: ChatPresentationContext) -> (CGSize, CGFloat, (CGSize, Bool, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))
|
||||
|
||||
if let node = node, let currentAsyncLayout = currentAsyncLayout {
|
||||
imageNode = node
|
||||
@ -2376,7 +2440,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
imageLayout = imageNode.asyncLayout()
|
||||
}
|
||||
|
||||
let (unboundSize, initialWidth, continueLayout) = imageLayout(context, presentationData, dateTimeFormat, message, associatedData, attributes, media, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext)
|
||||
let (unboundSize, initialWidth, continueLayout) = imageLayout(context, presentationData, dateTimeFormat, message, associatedData, attributes, media, mediaIndex, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext)
|
||||
|
||||
return (unboundSize, initialWidth, { constrainedSize, automaticPlayback, wideLayout, corners in
|
||||
let (finalWidth, finalLayout) = continueLayout(constrainedSize, automaticPlayback, wideLayout, corners)
|
||||
@ -2542,12 +2606,12 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
}
|
||||
|
||||
public func ignoreTapActionAtPoint(_ point: CGPoint) -> Bool {
|
||||
if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
||||
let convertedPoint = self.view.convert(point, to: extendedMediaOverlayNode.view)
|
||||
if extendedMediaOverlayNode.buttonNode.frame.contains(convertedPoint) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
||||
// let convertedPoint = self.view.convert(point, to: extendedMediaOverlayNode.view)
|
||||
// if extendedMediaOverlayNode.buttonNode.frame.contains(convertedPoint) {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var highlightedState: Bool = false
|
||||
|
||||
private var media: Media?
|
||||
private var mediaIndex: Int?
|
||||
private var automaticPlayback: Bool?
|
||||
|
||||
override public var visibility: ListViewItemNodeVisibility {
|
||||
@ -97,6 +98,8 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
return { item, layoutConstants, preparePosition, selection, constrainedSize, _ in
|
||||
var selectedMedia: Media?
|
||||
var selectedMediaIndex: Int?
|
||||
var extendedMedia: TelegramExtendedMedia?
|
||||
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
|
||||
var automaticPlayback: Bool = false
|
||||
var contentMode: InteractiveMediaNodeContentMode = .aspectFit
|
||||
@ -107,15 +110,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if selectedMedia == nil {
|
||||
for media in item.message.media {
|
||||
if let telegramImage = media as? TelegramMediaImage {
|
||||
// #if DEBUG
|
||||
// if item.message.text == "#" {
|
||||
// selectedMedia = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: 100, startParam: "", extendedMedia: .preview(dimensions: telegramImage.representations.first?.dimensions ?? PixelDimensions(width: 1, height: 1), immediateThumbnailData: telegramImage.immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
||||
// } else {
|
||||
// selectedMedia = telegramImage
|
||||
// }
|
||||
// #else
|
||||
selectedMedia = telegramImage
|
||||
// #endif
|
||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramImage) {
|
||||
automaticDownload = .full
|
||||
}
|
||||
@ -177,38 +172,50 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
contentMode = .aspectFill
|
||||
} else if let invoice = media as? TelegramMediaInvoice {
|
||||
selectedMedia = invoice
|
||||
|
||||
if let extendedMedia = invoice.extendedMedia, case let .full(media) = extendedMedia {
|
||||
if let telegramImage = media as? TelegramMediaImage {
|
||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramImage) {
|
||||
automaticDownload = .full
|
||||
}
|
||||
} else if let telegramFile = media as? TelegramMediaFile {
|
||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramFile) {
|
||||
automaticDownload = .full
|
||||
} else if shouldPredownloadMedia(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, media: telegramFile) {
|
||||
automaticDownload = .prefetch
|
||||
}
|
||||
|
||||
if !item.message.containsSecretMedia {
|
||||
if telegramFile.isAnimated && item.context.sharedContext.energyUsageSettings.autoplayGif {
|
||||
if case .full = automaticDownload {
|
||||
automaticPlayback = true
|
||||
} else {
|
||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
||||
}
|
||||
} else if (telegramFile.isVideo && !telegramFile.isAnimated) && item.context.sharedContext.energyUsageSettings.autoplayVideo {
|
||||
if case .full = automaticDownload {
|
||||
automaticPlayback = true
|
||||
} else {
|
||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
||||
}
|
||||
}
|
||||
}
|
||||
contentMode = .aspectFill
|
||||
extendedMedia = invoice.extendedMedia
|
||||
}
|
||||
else if let paidContent = media as? TelegramMediaPaidContent {
|
||||
selectedMedia = paidContent
|
||||
if case let .mosaic(_, _, index) = preparePosition, let index {
|
||||
extendedMedia = paidContent.extendedMedia[index]
|
||||
selectedMediaIndex = index
|
||||
} else {
|
||||
extendedMedia = paidContent.extendedMedia.first
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = selectedMediaIndex
|
||||
|
||||
if let extendedMedia, case let .full(media) = extendedMedia {
|
||||
if let telegramImage = media as? TelegramMediaImage {
|
||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramImage) {
|
||||
automaticDownload = .full
|
||||
}
|
||||
} else if let telegramFile = media as? TelegramMediaFile {
|
||||
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: telegramFile) {
|
||||
automaticDownload = .full
|
||||
} else if shouldPredownloadMedia(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, media: telegramFile) {
|
||||
automaticDownload = .prefetch
|
||||
}
|
||||
|
||||
if !item.message.containsSecretMedia {
|
||||
if telegramFile.isAnimated && item.context.sharedContext.energyUsageSettings.autoplayGif {
|
||||
if case .full = automaticDownload {
|
||||
automaticPlayback = true
|
||||
} else {
|
||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
||||
}
|
||||
} else if (telegramFile.isVideo && !telegramFile.isAnimated) && item.context.sharedContext.energyUsageSettings.autoplayVideo {
|
||||
if case .full = automaticDownload {
|
||||
automaticPlayback = true
|
||||
} else {
|
||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
||||
}
|
||||
}
|
||||
}
|
||||
contentMode = .aspectFill
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +357,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
)
|
||||
}
|
||||
|
||||
let (unboundSize, initialWidth, refineLayout) = interactiveImageLayout(item.context, item.presentationData, item.presentationData.dateTimeFormat, item.message, item.associatedData, item.attributes, selectedMedia!, dateAndStatus, automaticDownload, item.associatedData.automaticDownloadPeerType, item.associatedData.automaticDownloadPeerId, sizeCalculation, layoutConstants, contentMode, item.controllerInteraction.presentationContext)
|
||||
let (unboundSize, initialWidth, refineLayout) = interactiveImageLayout(item.context, item.presentationData, item.presentationData.dateTimeFormat, item.message, item.associatedData, item.attributes, selectedMedia!, selectedMediaIndex, dateAndStatus, automaticDownload, item.associatedData.automaticDownloadPeerType, item.associatedData.automaticDownloadPeerId, sizeCalculation, layoutConstants, contentMode, item.controllerInteraction.presentationContext)
|
||||
|
||||
let forceFullCorners = false
|
||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 7.0, hidesBackground: .emptyWallpaper, forceFullCorners: forceFullCorners, forceAlignment: .none)
|
||||
@ -386,6 +393,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if let strongSelf = self {
|
||||
strongSelf.item = item
|
||||
strongSelf.media = selectedMedia
|
||||
strongSelf.mediaIndex = selectedMediaIndex
|
||||
strongSelf.automaticPlayback = automaticPlayback
|
||||
|
||||
let imageFrame = CGRect(origin: CGPoint(x: bubbleInsets.left, y: bubbleInsets.top), size: imageSize)
|
||||
@ -441,6 +449,9 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if let invoice = currentMedia as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
currentMedia = fullMedia
|
||||
}
|
||||
if let paidContent = currentMedia as? TelegramMediaPaidContent, case let .full(fullMedia) = paidContent.extendedMedia[self.mediaIndex ?? 0] {
|
||||
currentMedia = fullMedia
|
||||
}
|
||||
if currentMedia.isSemanticallyEqual(to: media) {
|
||||
return self.interactiveImageNode.transitionNode(adjustRect: adjustRect)
|
||||
}
|
||||
@ -455,7 +466,9 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
if let invoice = currentMedia as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
currentMedia = fullMedia
|
||||
}
|
||||
|
||||
if let paidContent = currentMedia as? TelegramMediaPaidContent, case let .full(fullMedia) = paidContent.extendedMedia[self.mediaIndex ?? 0] {
|
||||
currentMedia = fullMedia
|
||||
}
|
||||
if let currentMedia = currentMedia, let media = media {
|
||||
for item in media {
|
||||
if item.isSemanticallyEqual(to: currentMedia) {
|
||||
|
@ -619,7 +619,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
|
||||
|
||||
let prepareLayout = messageNode.asyncLayoutContent()
|
||||
|
||||
let prepareContentPosition: ChatMessageBubblePreparePosition = .mosaic(top: .None(.None(.Incoming)), bottom: i == (items.count - 1 - 1) ? bottomPosition : .None(.None(.Incoming)))
|
||||
let prepareContentPosition: ChatMessageBubblePreparePosition = .mosaic(top: .None(.None(.Incoming)), bottom: i == (items.count - 1 - 1) ? bottomPosition : .None(.None(.Incoming)), index: i)
|
||||
|
||||
let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(items[i], layoutConstants, prepareContentPosition, nil, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), 0.0)
|
||||
maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth)
|
||||
|
@ -430,6 +430,13 @@ final class StarsStatisticsScreenComponent: Component {
|
||||
rate: starsState?.usdRate ?? 0.0
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent(
|
||||
theme: environment.theme,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
title: strings.Stars_BotRevenue_Proceeds_Current,
|
||||
value: starsState?.balances.currentBalance ?? 0,
|
||||
rate: starsState?.usdRate ?? 0.0
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 2, component: AnyComponent(StarsOverviewItemComponent(
|
||||
theme: environment.theme,
|
||||
dateTimeFormat: environment.dateTimeFormat,
|
||||
title: strings.Stars_BotRevenue_Proceeds_Total,
|
||||
|
@ -426,6 +426,14 @@ private final class SheetContent: CombinedComponent {
|
||||
}
|
||||
}, completion: { [weak controller] in
|
||||
let presentationData = accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let text: String
|
||||
if let _ = component.invoice.extendedMedia {
|
||||
text = presentationData.strings.Stars_Transfer_UnlockedText( presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string
|
||||
} else {
|
||||
text = presentationData.strings.Stars_Transfer_PurchasedText(invoice.title, botTitle, presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string
|
||||
}
|
||||
|
||||
if let navigationController = controller?.navigationController {
|
||||
Queue.mainQueue().after(0.5) {
|
||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||
@ -434,7 +442,7 @@ private final class SheetContent: CombinedComponent {
|
||||
content: .image(
|
||||
image: UIImage(bundleImageName: "Premium/Stars/StarLarge")!,
|
||||
title: presentationData.strings.Stars_Transfer_PurchasedTitle,
|
||||
text: presentationData.strings.Stars_Transfer_PurchasedText(invoice.title, botTitle, presentationData.strings.Stars_Transfer_Purchased_Stars(Int32(invoice.totalAmount))).string,
|
||||
text: text,
|
||||
round: false,
|
||||
undoText: nil
|
||||
),
|
||||
|
@ -78,18 +78,6 @@ extension ChatControllerImpl {
|
||||
}))
|
||||
)
|
||||
|
||||
if canAddToReadingList {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_AddToReadingList, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
if let link = URL(string: url) {
|
||||
let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil)
|
||||
}
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuCopyLink, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
@ -103,7 +91,19 @@ extension ChatControllerImpl {
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .copy(text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
}))
|
||||
)
|
||||
|
||||
|
||||
if canAddToReadingList {
|
||||
items.append(
|
||||
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_AddToReadingList, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
if let link = URL(string: url) {
|
||||
let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil)
|
||||
}
|
||||
}))
|
||||
)
|
||||
}
|
||||
|
||||
self.canReadHistory.set(false)
|
||||
|
||||
let controller = ContextController(presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(items))), recognizer: recognizer, gesture: gesture, disableScreenshots: false)
|
||||
|
@ -937,7 +937,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
// }
|
||||
// #endif
|
||||
|
||||
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||
if let paidContent = media as? TelegramMediaPaidContent, let extendedMedia = paidContent.extendedMedia.first {
|
||||
switch extendedMedia {
|
||||
case .preview:
|
||||
if displayVoiceMessageDiscardAlert() {
|
||||
strongSelf.controllerInteraction?.openCheckoutOrReceipt(message.id)
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case .full:
|
||||
break
|
||||
}
|
||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
||||
switch extendedMedia {
|
||||
case .preview:
|
||||
if displayVoiceMessageDiscardAlert() {
|
||||
@ -2633,7 +2645,36 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
for media in message.media {
|
||||
if let invoice = media as? TelegramMediaInvoice {
|
||||
if let paidContent = media as? TelegramMediaPaidContent {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
let inputData = Promise<BotCheckoutController.InputData?>()
|
||||
inputData.set(BotCheckoutController.InputData.fetch(context: strongSelf.context, source: .message(message.id))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<BotCheckoutController.InputData?, NoError> in
|
||||
return .single(nil)
|
||||
})
|
||||
if let starsContext = strongSelf.context.starsContext {
|
||||
let starsInputData = combineLatest(
|
||||
inputData.get(),
|
||||
starsContext.state
|
||||
)
|
||||
|> map { data, state -> (StarsContext.State, BotPaymentForm, EnginePeer?)? in
|
||||
if let data, let state {
|
||||
return (state, data.form, data.botPeer)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
let _ = (starsInputData |> filter { $0 != nil } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||
guard let strongSelf = self, let extendedMedia = paidContent.extendedMedia.first, case let .preview(dimensions, immediateThumbnailData, _) = extendedMedia else {
|
||||
return
|
||||
}
|
||||
let invoice = TelegramMediaInvoice(title: "", description: "", photo: nil, receiptMessageId: nil, currency: "XTR", totalAmount: paidContent.amount, startParam: "", extendedMedia: .preview(dimensions:dimensions, immediateThumbnailData: immediateThumbnailData, videoDuration: nil), flags: [], version: 0)
|
||||
let controller = strongSelf.context.sharedContext.makeStarsTransferScreen(context: strongSelf.context, starsContext: starsContext, invoice: invoice, source: .message(messageId), inputData: starsInputData, completion: { _ in })
|
||||
strongSelf.push(controller)
|
||||
})
|
||||
}
|
||||
} else if let invoice = media as? TelegramMediaInvoice {
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
if let receiptMessageId = invoice.receiptMessageId {
|
||||
if invoice.currency == "XTR" {
|
||||
|
@ -2655,6 +2655,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
||||
if invoice.version != TelegramMediaInvoice.lastVersion {
|
||||
contentRequiredValidation = true
|
||||
}
|
||||
} else if let paidContent = media as? TelegramMediaPaidContent, let extendedMedia = paidContent.extendedMedia.first, case .preview = extendedMedia {
|
||||
messageIdsWithInactiveExtendedMedia.insert(message.id)
|
||||
} else if let _ = media as? TelegramMediaStory {
|
||||
storiesRequiredValidation = true
|
||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.story {
|
||||
|
@ -1711,7 +1711,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
clearCacheAsDelete = true
|
||||
}
|
||||
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info, canEditFactCheck(appConfig: appConfig) {
|
||||
if message.id.namespace == Namespaces.Message.Cloud, let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info, canEditFactCheck(appConfig: appConfig) {
|
||||
var canAddFactCheck = true
|
||||
if message.media.contains(where: { $0 is TelegramMediaAction || $0 is TelegramMediaGiveaway }) {
|
||||
canAddFactCheck = false
|
||||
@ -2190,6 +2190,8 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
|
||||
for media in message.media {
|
||||
if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||
isShareProtected = true
|
||||
} else if let _ = media as? TelegramMediaPaidContent {
|
||||
isShareProtected = true
|
||||
} else if let file = media as? TelegramMediaFile, file.isSticker {
|
||||
for case let .Sticker(_, packReference, _) in file.attributes {
|
||||
if let _ = packReference {
|
||||
|
Loading…
x
Reference in New Issue
Block a user