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.PurchasedText" = "You acquired **%1$@** in **%2$@** for **%3$@**.";
|
||||||
"Stars.Transfer.Purchased.Stars_1" = "%@ Star";
|
"Stars.Transfer.Purchased.Stars_1" = "%@ Star";
|
||||||
"Stars.Transfer.Purchased.Stars_any" = "%@ Stars";
|
"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.UnlockInfo" = "Do you want to unlock media for **%1$@**?";
|
||||||
|
|
||||||
"Stars.Transfer.Balance" = "Balance";
|
"Stars.Transfer.Balance" = "Balance";
|
||||||
@ -12351,6 +12352,7 @@ Sorry for the inconvenience.";
|
|||||||
"Stars.BotRevenue.Revenue.Title" = "Revenue";
|
"Stars.BotRevenue.Revenue.Title" = "Revenue";
|
||||||
"Stars.BotRevenue.Proceeds.Title" = "Proceeds Overview";
|
"Stars.BotRevenue.Proceeds.Title" = "Proceeds Overview";
|
||||||
"Stars.BotRevenue.Proceeds.Available" = "Available Balance";
|
"Stars.BotRevenue.Proceeds.Available" = "Available Balance";
|
||||||
|
"Stars.BotRevenue.Proceeds.Current" = "Total Balance";
|
||||||
"Stars.BotRevenue.Proceeds.Total" = "Total Lifetime Proceeds";
|
"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.";
|
"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 {
|
if messageText.isEmpty, case let .Loaded(content) = webpage.content {
|
||||||
messageText = content.displayUrl
|
messageText = content.displayUrl
|
||||||
}
|
}
|
||||||
|
case _ as TelegramMediaPaidContent:
|
||||||
|
if message.text.isEmpty {
|
||||||
|
messageText = "Paid Media"
|
||||||
|
} else {
|
||||||
|
messageText = "🖼 \(messageText)"
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,10 @@ public func chatMessageGalleryControllerData(context: AccountContext, chatLocati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for media in message.media {
|
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
|
standalone = true
|
||||||
galleryMedia = fullMedia
|
galleryMedia = fullMedia
|
||||||
} else if let action = media as? TelegramMediaAction {
|
} else if let action = media as? TelegramMediaAction {
|
||||||
|
@ -1622,7 +1622,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||||||
|
|
||||||
var hasExternalShare = true
|
var hasExternalShare = true
|
||||||
for media in currentMessage.media {
|
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
|
hasExternalShare = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,9 @@ private func tagsForMessage(_ message: Message) -> MessageTags? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func galleryMediaForMedia(media: Media) -> Media? {
|
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
|
return fullMedia
|
||||||
} else if let media = media as? TelegramMediaImage {
|
} else if let media = media as? TelegramMediaImage {
|
||||||
return media
|
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)
|
node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret)
|
||||||
for media in self.message.media {
|
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))
|
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
||||||
} else if let image = media as? TelegramMediaImage {
|
} else if let image = media as? TelegramMediaImage {
|
||||||
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
node.setImage(userLocation: .peer(self.message.id.peerId), imageReference: .message(message: MessageReference(self.message), media: image))
|
||||||
|
@ -942,6 +942,7 @@
|
|||||||
NSInteger num = 0;
|
NSInteger num = 0;
|
||||||
bool grouping = selectionContext.grouping;
|
bool grouping = selectionContext.grouping;
|
||||||
|
|
||||||
|
NSNumber *price;
|
||||||
bool hasAnyTimers = false;
|
bool hasAnyTimers = false;
|
||||||
if (editingContext != nil || grouping)
|
if (editingContext != nil || grouping)
|
||||||
{
|
{
|
||||||
@ -950,6 +951,9 @@
|
|||||||
if ([editingContext timerForItem:asset] != nil) {
|
if ([editingContext timerForItem:asset] != nil) {
|
||||||
hasAnyTimers = true;
|
hasAnyTimers = true;
|
||||||
}
|
}
|
||||||
|
if (price == nil) {
|
||||||
|
price = [editingContext priceForItem:asset];
|
||||||
|
}
|
||||||
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:asset];
|
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:asset];
|
||||||
if ([adjustments isKindOfClass:[TGVideoEditAdjustments class]]) {
|
if ([adjustments isKindOfClass:[TGVideoEditAdjustments class]]) {
|
||||||
TGVideoEditAdjustments *videoAdjustments = (TGVideoEditAdjustments *)adjustments;
|
TGVideoEditAdjustments *videoAdjustments = (TGVideoEditAdjustments *)adjustments;
|
||||||
@ -1057,6 +1061,9 @@
|
|||||||
else if (groupedId != nil && !hasAnyTimers)
|
else if (groupedId != nil && !hasAnyTimers)
|
||||||
dict[@"groupedId"] = groupedId;
|
dict[@"groupedId"] = groupedId;
|
||||||
|
|
||||||
|
if (price != nil)
|
||||||
|
dict[@"price"] = price;
|
||||||
|
|
||||||
if (spoiler) {
|
if (spoiler) {
|
||||||
dict[@"spoiler"] = @true;
|
dict[@"spoiler"] = @true;
|
||||||
}
|
}
|
||||||
@ -1137,6 +1144,9 @@
|
|||||||
else if (groupedId != nil && !hasAnyTimers)
|
else if (groupedId != nil && !hasAnyTimers)
|
||||||
dict[@"groupedId"] = groupedId;
|
dict[@"groupedId"] = groupedId;
|
||||||
|
|
||||||
|
if (price != nil)
|
||||||
|
dict[@"price"] = price;
|
||||||
|
|
||||||
if (spoiler) {
|
if (spoiler) {
|
||||||
dict[@"spoiler"] = @true;
|
dict[@"spoiler"] = @true;
|
||||||
}
|
}
|
||||||
@ -1261,6 +1271,9 @@
|
|||||||
if (groupedId != nil)
|
if (groupedId != nil)
|
||||||
dict[@"groupedId"] = groupedId;
|
dict[@"groupedId"] = groupedId;
|
||||||
|
|
||||||
|
if (price != nil)
|
||||||
|
dict[@"price"] = price;
|
||||||
|
|
||||||
if (spoiler) {
|
if (spoiler) {
|
||||||
dict[@"spoiler"] = @true;
|
dict[@"spoiler"] = @true;
|
||||||
}
|
}
|
||||||
@ -1334,6 +1347,9 @@
|
|||||||
else if (groupedId != nil && !hasAnyTimers)
|
else if (groupedId != nil && !hasAnyTimers)
|
||||||
dict[@"groupedId"] = groupedId;
|
dict[@"groupedId"] = groupedId;
|
||||||
|
|
||||||
|
if (price != nil)
|
||||||
|
dict[@"price"] = price;
|
||||||
|
|
||||||
if (spoiler) {
|
if (spoiler) {
|
||||||
dict[@"spoiler"] = @true;
|
dict[@"spoiler"] = @true;
|
||||||
}
|
}
|
||||||
@ -1415,6 +1431,9 @@
|
|||||||
if (timer != nil)
|
if (timer != nil)
|
||||||
dict[@"timer"] = timer;
|
dict[@"timer"] = timer;
|
||||||
|
|
||||||
|
if (price != nil)
|
||||||
|
dict[@"price"] = price;
|
||||||
|
|
||||||
if (spoiler) {
|
if (spoiler) {
|
||||||
dict[@"spoiler"] = @true;
|
dict[@"spoiler"] = @true;
|
||||||
}
|
}
|
||||||
|
@ -134,13 +134,15 @@ private final class LegacyAssetItemWrapper: NSObject {
|
|||||||
let item: LegacyAssetItem
|
let item: LegacyAssetItem
|
||||||
let timer: Int?
|
let timer: Int?
|
||||||
let spoiler: Bool?
|
let spoiler: Bool?
|
||||||
|
let price: Int64?
|
||||||
let groupedId: Int64?
|
let groupedId: Int64?
|
||||||
let uniqueId: String?
|
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.item = item
|
||||||
self.timer = timer
|
self.timer = timer
|
||||||
self.spoiler = spoiler
|
self.spoiler = spoiler
|
||||||
|
self.price = price
|
||||||
self.groupedId = groupedId
|
self.groupedId = groupedId
|
||||||
self.uniqueId = uniqueId
|
self.uniqueId = uniqueId
|
||||||
|
|
||||||
@ -159,6 +161,9 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} ?? []
|
} ?? []
|
||||||
|
|
||||||
|
let price = dict["price"] as? Int64
|
||||||
|
|
||||||
if (dict["type"] as! NSString) == "editedPhoto" || (dict["type"] as! NSString) == "capturedPhoto" {
|
if (dict["type"] as! NSString) == "editedPhoto" || (dict["type"] as! NSString) == "capturedPhoto" {
|
||||||
let image = dict["image"] as! UIImage
|
let image = dict["image"] as! UIImage
|
||||||
let thumbnail = dict["previewImage"] 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
|
let url: String? = (dict["url"] as? String) ?? (dict["url"] as? URL)?.path
|
||||||
if let url = url {
|
if let url = url {
|
||||||
let dimensions = image.size
|
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 {
|
} 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
|
return result
|
||||||
} else if (dict["type"] as! NSString) == "cloudPhoto" {
|
} else if (dict["type"] as! NSString) == "cloudPhoto" {
|
||||||
@ -192,9 +197,9 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
|||||||
name = customName
|
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 {
|
} 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
|
return result
|
||||||
} else if (dict["type"] as! NSString) == "file" {
|
} 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 dimensions = (dict["dimensions"]! as AnyObject).cgSizeValue!
|
||||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
var result: [AnyHashable: Any] = [:]
|
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
|
return result
|
||||||
}
|
}
|
||||||
} else if (dict["type"] as! NSString) == "video" {
|
} else if (dict["type"] as! NSString) == "video" {
|
||||||
@ -232,13 +237,13 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
|||||||
|
|
||||||
if let asset = dict["asset"] as? TGMediaAsset {
|
if let asset = dict["asset"] as? TGMediaAsset {
|
||||||
var result: [AnyHashable: Any] = [:]
|
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
|
return result
|
||||||
} else if let url = (dict["url"] as? String) ?? (dict["url"] as? URL)?.absoluteString {
|
} else if let url = (dict["url"] as? String) ?? (dict["url"] as? URL)?.absoluteString {
|
||||||
let dimensions = (dict["dimensions"]! as AnyObject).cgSizeValue!
|
let dimensions = (dict["dimensions"]! as AnyObject).cgSizeValue!
|
||||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
||||||
var result: [AnyHashable: Any] = [:]
|
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
|
return result
|
||||||
}
|
}
|
||||||
} else if (dict["type"] as! NSString) == "cameraVideo" {
|
} else if (dict["type"] as! NSString) == "cameraVideo" {
|
||||||
@ -254,7 +259,7 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
|
|||||||
let dimensions = previewImage.pixelSize()
|
let dimensions = previewImage.pixelSize()
|
||||||
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
let duration = (dict["duration"]! as AnyObject).doubleValue!
|
||||||
var result: [AnyHashable: Any] = [:]
|
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
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -356,6 +361,15 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
|
|||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let disposable = SSignal.combineSignals(signals).start(next: { anyValues in
|
let disposable = SSignal.combineSignals(signals).start(next: { anyValues in
|
||||||
var messages: [LegacyAssetPickerEnqueueMessage] = []
|
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) {
|
outer: for item in (anyValues as! NSArray) {
|
||||||
if let item = (item as? NSDictionary)?.object(forKey: "item") as? LegacyAssetItemWrapper {
|
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):
|
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:
|
case .tempFile:
|
||||||
break
|
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):
|
case let .asset(asset):
|
||||||
var randomId: Int64 = 0
|
var randomId: Int64 = 0
|
||||||
arc4random_buf(&randomId, 8)
|
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:
|
default:
|
||||||
break
|
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.putNext(messages)
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
|
@ -552,9 +552,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||||||
let priceSignal = Signal<Int64?, NoError> { subscriber in
|
let priceSignal = Signal<Int64?, NoError> { subscriber in
|
||||||
if let signal = editingContext.priceSignal(forIdentifier: asset.localIdentifier) {
|
if let signal = editingContext.priceSignal(forIdentifier: asset.localIdentifier) {
|
||||||
let disposable = signal.start(next: { next in
|
let disposable = signal.start(next: { next in
|
||||||
if let next = next as? Int64 {
|
subscriber.putNext(next as? Int64)
|
||||||
subscriber.putNext(next)
|
|
||||||
}
|
|
||||||
}, error: { _ in
|
}, error: { _ in
|
||||||
}, completed: nil)!
|
}, completed: nil)!
|
||||||
|
|
||||||
@ -681,6 +679,10 @@ final class MediaPickerGridItemNode: GridItemNode {
|
|||||||
}
|
}
|
||||||
backgroundNode.addSubnode(labelNode)
|
backgroundNode.addSubnode(labelNode)
|
||||||
backgroundNode.addSubnode(iconNode)
|
backgroundNode.addSubnode(iconNode)
|
||||||
|
|
||||||
|
self.priceBackgroundNode = backgroundNode
|
||||||
|
self.priceLabelNode = labelNode
|
||||||
|
self.priceIconNode = iconNode
|
||||||
}
|
}
|
||||||
labelNode.attributedText = NSAttributedString(string: "\(price)", font: Font.semibold(15.0), textColor: .white)
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2013,7 +2028,6 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
self.updateSelectionState(count: Int32(selectionContext.count()))
|
self.updateSelectionState(count: Int32(selectionContext.count()))
|
||||||
|
|
||||||
|
|
||||||
if case let .assets(_, mode) = self.subject, case .createSticker = mode {
|
if case let .assets(_, mode) = self.subject, case .createSticker = mode {
|
||||||
let _ = cutoutAvailability(context: context).startStandalone()
|
let _ = cutoutAvailability(context: context).startStandalone()
|
||||||
}
|
}
|
||||||
@ -2434,9 +2448,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hasSpoilers = false
|
var hasSpoilers = false
|
||||||
|
var price: Int64?
|
||||||
var hasGeneric = false
|
var hasGeneric = false
|
||||||
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState {
|
||||||
for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
|
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) {
|
if editingContext.spoiler(for: item) {
|
||||||
hasSpoilers = true
|
hasSpoilers = true
|
||||||
} else {
|
} else {
|
||||||
@ -2456,8 +2474,11 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
)
|
)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
|> map { [weak self] grouped, isCaptionAboveMediaAvailable -> ContextController.Items in
|
|> map { [weak self] grouped, isCaptionAboveMediaAvailable -> ContextController.Items in
|
||||||
|
guard let self else {
|
||||||
|
return ContextController.Items(content: .list([]))
|
||||||
|
}
|
||||||
var items: [ContextMenuItem] = []
|
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
|
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)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/File"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, f in
|
}, 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: {})
|
self?.controllerNode.send(asFile: true, silently: false, scheduleTime: nil, animated: true, parameters: nil, completion: {})
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
if selectionCount > 1 {
|
if selectionCount > 1, price == nil {
|
||||||
// items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: "Send Without Grouping", icon: { theme in
|
||||||
// return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/GroupingOff"), color: theme.contextMenu.primaryColor)
|
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)
|
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
f(.default)
|
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?.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 isSpoilerAvailable || isPaidAvailable || (selectionCount > 0 && isCaptionAboveMediaAvailable) {
|
||||||
if !items.isEmpty {
|
if !items.isEmpty {
|
||||||
items.append(.separator)
|
items.append(.separator)
|
||||||
@ -2509,7 +2533,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
|
|
||||||
if isCaptionAboveMediaAvailable {
|
if isCaptionAboveMediaAvailable {
|
||||||
var mediaCaptionIsAbove = false
|
var mediaCaptionIsAbove = false
|
||||||
if let interaction = self?.interaction {
|
if let interaction = self.interaction {
|
||||||
mediaCaptionIsAbove = interaction.captionIsAboveMedia
|
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(
|
items.append(.action(ContextMenuActionItem(text: hasGeneric ? strings.Attachment_EnableSpoiler : strings.Attachment_DisableSpoiler, icon: { _ in return nil }, iconAnimation: ContextMenuActionItem.IconAnimation(
|
||||||
name: "anim_spoiler",
|
name: "anim_spoiler",
|
||||||
loop: true
|
loop: true
|
||||||
@ -2544,7 +2568,16 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
if isPaidAvailable {
|
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)
|
return generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Paid"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
@ -130,12 +130,27 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.spoilerDisposable.set((spoilerSignal
|
let priceSignal = Signal<Int64?, NoError> { subscriber in
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] hasSpoiler 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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.updateHasSpoiler(hasSpoiler)
|
strongSelf.updateHasSpoiler(hasSpoiler, price: price)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,14 +178,14 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var didSetupSpoiler = false
|
private var didSetupSpoiler = false
|
||||||
private func updateHasSpoiler(_ hasSpoiler: Bool) {
|
private func updateHasSpoiler(_ hasSpoiler: Bool, price: Int64?) {
|
||||||
var animated = true
|
var animated = true
|
||||||
if !self.didSetupSpoiler {
|
if !self.didSetupSpoiler {
|
||||||
animated = false
|
animated = false
|
||||||
self.didSetupSpoiler = true
|
self.didSetupSpoiler = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasSpoiler {
|
if hasSpoiler || price != nil {
|
||||||
if self.spoilerNode == nil {
|
if self.spoilerNode == nil {
|
||||||
let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations)
|
let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations)
|
||||||
self.insertSubnode(spoilerNode, aboveSubnode: self.imageNode)
|
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[-1759532989] = { return Api.InputMedia.parse_inputMediaGeoLive($0) }
|
||||||
dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) }
|
dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) }
|
||||||
dict[1080028941] = { return Api.InputMedia.parse_inputMediaInvoice($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[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
|
||||||
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
|
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
|
||||||
dict[261416433] = { return Api.InputMedia.parse_inputMediaPoll($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[-626162256] = { return Api.MessageMedia.parse_messageMediaGiveaway($0) }
|
||||||
dict[-963047320] = { return Api.MessageMedia.parse_messageMediaGiveawayResults($0) }
|
dict[-963047320] = { return Api.MessageMedia.parse_messageMediaGiveawayResults($0) }
|
||||||
dict[-156940077] = { return Api.MessageMedia.parse_messageMediaInvoice($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[1766936791] = { return Api.MessageMedia.parse_messageMediaPhoto($0) }
|
||||||
dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
|
dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
|
||||||
dict[1758159491] = { return Api.MessageMedia.parse_messageMediaStory($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[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||||
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
|
dict[2033461574] = { return Api.StarsRevenueStatus.parse_starsRevenueStatus($0) }
|
||||||
dict[198776256] = { return Api.StarsTopupOption.parse_starsTopupOption($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[-670195363] = { return Api.StarsTransactionPeer.parse_starsTransactionPeer($0) }
|
||||||
dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) }
|
dict[-1269320843] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerAppStore($0) }
|
||||||
dict[-382740222] = { return Api.StarsTransactionPeer.parse_starsTransactionPeerFragment($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[1442983757] = { return Api.Update.parse_updateLangPack($0) }
|
||||||
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
|
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
|
||||||
dict[1448076945] = { return Api.Update.parse_updateLoginToken($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[1318109142] = { return Api.Update.parse_updateMessageID($0) }
|
||||||
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
|
||||||
dict[619974263] = { return Api.Update.parse_updateMessagePollVote($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 inputMediaGeoLive(flags: Int32, geoPoint: Api.InputGeoPoint, heading: Int32?, period: Int32?, proximityNotificationRadius: Int32?)
|
||||||
case inputMediaGeoPoint(geoPoint: Api.InputGeoPoint)
|
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 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 inputMediaPhoto(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?)
|
||||||
case inputMediaPhotoExternal(flags: Int32, url: String, ttlSeconds: Int32?)
|
case inputMediaPhotoExternal(flags: Int32, url: String, ttlSeconds: Int32?)
|
||||||
case inputMediaPoll(flags: Int32, poll: Api.Poll, correctAnswers: [Buffer]?, solution: String?, solutionEntities: [Api.MessageEntity]?)
|
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 << 1) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 2) != 0 {extendedMedia!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 2) != 0 {extendedMedia!.serialize(buffer, true)}
|
||||||
break
|
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):
|
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(-1279654347)
|
buffer.appendInt32(-1279654347)
|
||||||
@ -210,6 +222,8 @@ public extension Api {
|
|||||||
return ("inputMediaGeoPoint", [("geoPoint", geoPoint as Any)])
|
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):
|
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)])
|
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):
|
case .inputMediaPhoto(let flags, let id, let ttlSeconds):
|
||||||
return ("inputMediaPhoto", [("flags", flags as Any), ("id", id as Any), ("ttlSeconds", ttlSeconds as Any)])
|
return ("inputMediaPhoto", [("flags", flags as Any), ("id", id as Any), ("ttlSeconds", ttlSeconds as Any)])
|
||||||
case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds):
|
case .inputMediaPhotoExternal(let flags, let url, let ttlSeconds):
|
||||||
@ -399,6 +413,22 @@ public extension Api {
|
|||||||
return nil
|
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? {
|
public static func parse_inputMediaPhoto(_ reader: BufferReader) -> InputMedia? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_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 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 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 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 messageMediaPhoto(flags: Int32, photo: Api.Photo?, ttlSeconds: Int32?)
|
||||||
case messageMediaPoll(poll: Api.Poll, results: Api.PollResults)
|
case messageMediaPoll(poll: Api.Poll, results: Api.PollResults)
|
||||||
case messageMediaStory(flags: Int32, peer: Api.Peer, id: Int32, story: Api.StoryItem?)
|
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)
|
serializeString(startParam, buffer: buffer, boxed: false)
|
||||||
if Int(flags) & Int(1 << 4) != 0 {extendedMedia!.serialize(buffer, true)}
|
if Int(flags) & Int(1 << 4) != 0 {extendedMedia!.serialize(buffer, true)}
|
||||||
break
|
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):
|
case .messageMediaPhoto(let flags, let photo, let ttlSeconds):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1766936791)
|
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)])
|
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):
|
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)])
|
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):
|
case .messageMediaPhoto(let flags, let photo, let ttlSeconds):
|
||||||
return ("messageMediaPhoto", [("flags", flags as Any), ("photo", photo as Any), ("ttlSeconds", ttlSeconds as Any)])
|
return ("messageMediaPhoto", [("flags", flags as Any), ("photo", photo as Any), ("ttlSeconds", ttlSeconds as Any)])
|
||||||
case .messageMediaPoll(let poll, let results):
|
case .messageMediaPoll(let poll, let results):
|
||||||
@ -1149,6 +1163,22 @@ public extension Api {
|
|||||||
return nil
|
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? {
|
public static func parse_messageMediaPhoto(_ reader: BufferReader) -> MessageMedia? {
|
||||||
var _1: Int32?
|
var _1: Int32?
|
||||||
_1 = reader.readInt32()
|
_1 = reader.readInt32()
|
||||||
|
@ -708,13 +708,13 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum StarsTransaction: TypeConstructorDescription {
|
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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(-1442789224)
|
buffer.appendInt32(-901959922)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeString(id, 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 << 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 {serializeInt32(transactionDate!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 5) != 0 {serializeString(transactionUrl!, 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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
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):
|
||||||
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)])
|
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() }
|
if Int(_1!) & Int(1 << 5) != 0 {_9 = reader.readInt32() }
|
||||||
var _10: String?
|
var _10: String?
|
||||||
if Int(_1!) & Int(1 << 5) != 0 {_10 = parseString(reader) }
|
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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -772,8 +778,10 @@ public extension Api {
|
|||||||
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
|
let _c8 = (Int(_1!) & Int(1 << 2) == 0) || _8 != nil
|
||||||
let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil
|
let _c9 = (Int(_1!) & Int(1 << 5) == 0) || _9 != nil
|
||||||
let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil
|
let _c10 = (Int(_1!) & Int(1 << 5) == 0) || _10 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
let _c11 = (Int(_1!) & Int(1 << 7) == 0) || _11 != nil
|
||||||
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 _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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -321,7 +321,7 @@ public extension Api {
|
|||||||
case updateLangPack(difference: Api.LangPackDifference)
|
case updateLangPack(difference: Api.LangPackDifference)
|
||||||
case updateLangPackTooLong(langCode: String)
|
case updateLangPackTooLong(langCode: String)
|
||||||
case updateLoginToken
|
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 updateMessageID(id: Int32, randomId: Int64)
|
||||||
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
|
case updateMessagePoll(flags: Int32, pollId: Int64, poll: Api.Poll?, results: Api.PollResults)
|
||||||
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32)
|
case updateMessagePollVote(pollId: Int64, peer: Api.Peer, options: [Buffer], qts: Int32)
|
||||||
@ -1039,11 +1039,15 @@ public extension Api {
|
|||||||
break
|
break
|
||||||
case .updateMessageExtendedMedia(let peer, let msgId, let extendedMedia):
|
case .updateMessageExtendedMedia(let peer, let msgId, let extendedMedia):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(1517529484)
|
buffer.appendInt32(-710666460)
|
||||||
}
|
}
|
||||||
peer.serialize(buffer, true)
|
peer.serialize(buffer, true)
|
||||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
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
|
break
|
||||||
case .updateMessageID(let id, let randomId):
|
case .updateMessageID(let id, let randomId):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -3241,9 +3245,9 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
var _2: Int32?
|
var _2: Int32?
|
||||||
_2 = reader.readInt32()
|
_2 = reader.readInt32()
|
||||||
var _3: Api.MessageExtendedMedia?
|
var _3: [Api.MessageExtendedMedia]?
|
||||||
if let signature = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parse(reader, signature: signature) as? Api.MessageExtendedMedia
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageExtendedMedia.self)
|
||||||
}
|
}
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
|
@ -120,7 +120,7 @@ enum AccountStateMutationOperation {
|
|||||||
case UpdateAttachMenuBots
|
case UpdateAttachMenuBots
|
||||||
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
case UpdateAudioTranscription(messageId: MessageId, id: Int64, isPending: Bool, text: String)
|
||||||
case UpdateConfig
|
case UpdateConfig
|
||||||
case UpdateExtendedMedia(MessageId, Api.MessageExtendedMedia)
|
case UpdateExtendedMedia(MessageId, [Api.MessageExtendedMedia])
|
||||||
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
|
case ResetForumTopic(topicId: MessageId, data: StoreMessageHistoryThreadData, pts: Int32)
|
||||||
case UpdateStory(peerId: PeerId, story: Api.StoryItem)
|
case UpdateStory(peerId: PeerId, story: Api.StoryItem)
|
||||||
case UpdateReadStories(peerId: PeerId, maxId: Int32)
|
case UpdateReadStories(peerId: PeerId, maxId: Int32)
|
||||||
@ -652,7 +652,7 @@ struct AccountMutableState {
|
|||||||
self.addOperation(.UpdateConfig)
|
self.addOperation(.UpdateConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutating func updateExtendedMedia(_ messageId: MessageId, extendedMedia: Api.MessageExtendedMedia) {
|
mutating func updateExtendedMedia(_ messageId: MessageId, extendedMedia: [Api.MessageExtendedMedia]) {
|
||||||
self.addOperation(.UpdateExtendedMedia(messageId, extendedMedia))
|
self.addOperation(.UpdateExtendedMedia(messageId, extendedMedia))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +226,7 @@ private var declaredEncodables: Void = {
|
|||||||
declareEncodable(OutgoingQuickReplyMessageAttribute.self, f: { OutgoingQuickReplyMessageAttribute(decoder: $0) })
|
declareEncodable(OutgoingQuickReplyMessageAttribute.self, f: { OutgoingQuickReplyMessageAttribute(decoder: $0) })
|
||||||
declareEncodable(EffectMessageAttribute.self, f: { EffectMessageAttribute(decoder: $0) })
|
declareEncodable(EffectMessageAttribute.self, f: { EffectMessageAttribute(decoder: $0) })
|
||||||
declareEncodable(FactCheckMessageAttribute.self, f: { FactCheckMessageAttribute(decoder: $0) })
|
declareEncodable(FactCheckMessageAttribute.self, f: { FactCheckMessageAttribute(decoder: $0) })
|
||||||
|
declareEncodable(TelegramMediaPaidContent.self, f: { TelegramMediaPaidContent(decoder: $0) })
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -391,33 +391,7 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
|||||||
if (flags & (1 << 1)) != 0 {
|
if (flags & (1 << 1)) != 0 {
|
||||||
parsedFlags.insert(.shippingAddressRequested)
|
parsedFlags.insert(.shippingAddressRequested)
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
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)
|
|
||||||
case let .messageMediaPoll(poll, results):
|
case let .messageMediaPoll(poll, results):
|
||||||
switch poll {
|
switch poll {
|
||||||
case let .poll(id, flags, question, answers, closePeriod, _):
|
case let .poll(id, flags, question, answers, closePeriod, _):
|
||||||
@ -464,6 +438,8 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
|||||||
flags.insert(.refunded)
|
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)
|
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>? {
|
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 let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) {
|
||||||
if peerId.namespace == Namespaces.Peer.SecretChat, let resource = largest.resource as? SecretFileMediaResource {
|
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)))
|
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
|
transaction.updateMessage(messageId, update: { currentMessage in
|
||||||
var media = currentMessage.media
|
var media = currentMessage.media
|
||||||
let invoice = media.first(where: { $0 is TelegramMediaInvoice }) as? TelegramMediaInvoice
|
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?
|
var storeForwardInfo: StoreMessageForwardInfo?
|
||||||
if let forwardInfo = currentMessage.forwardInfo {
|
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)
|
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?
|
let updatedExtendedMedia = apiExtendedMedia.compactMap { TelegramExtendedMedia(apiExtendedMedia: $0, peerId: messageId.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()
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let updatedExtendedMedia = updatedExtendedMedia, var invoice = invoice {
|
if let first = updatedExtendedMedia.first, case .full = first {
|
||||||
if let currentExtendedMedia = currentExtendedMedia, case .full = currentExtendedMedia, case .preview = updatedExtendedMedia {
|
if var invoice = invoice {
|
||||||
|
|
||||||
} else {
|
|
||||||
media = media.filter { !($0 is TelegramMediaInvoice) }
|
media = media.filter { !($0 is TelegramMediaInvoice) }
|
||||||
invoice = invoice.withUpdatedExtendedMedia(updatedExtendedMedia)
|
invoice = invoice.withUpdatedExtendedMedia(first)
|
||||||
media.append(invoice)
|
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))
|
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 class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 182
|
return 183
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
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 story(TelegramMediaStory)
|
||||||
case giveaway(TelegramMediaGiveaway)
|
case giveaway(TelegramMediaGiveaway)
|
||||||
case giveawayResults(TelegramMediaGiveawayResults)
|
case giveawayResults(TelegramMediaGiveawayResults)
|
||||||
|
case paidContent(TelegramMediaPaidContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension EngineMedia {
|
public extension EngineMedia {
|
||||||
@ -56,6 +57,8 @@ public extension EngineMedia {
|
|||||||
return giveaway.id
|
return giveaway.id
|
||||||
case let .giveawayResults(giveawayResults):
|
case let .giveawayResults(giveawayResults):
|
||||||
return giveawayResults.id
|
return giveawayResults.id
|
||||||
|
case let .paidContent(paidContent):
|
||||||
|
return paidContent.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,6 +98,8 @@ public extension EngineMedia {
|
|||||||
self = .giveaway(giveaway)
|
self = .giveaway(giveaway)
|
||||||
case let giveawayResults as TelegramMediaGiveawayResults:
|
case let giveawayResults as TelegramMediaGiveawayResults:
|
||||||
self = .giveawayResults(giveawayResults)
|
self = .giveawayResults(giveawayResults)
|
||||||
|
case let paidContent as TelegramMediaPaidContent:
|
||||||
|
self = .paidContent(paidContent)
|
||||||
default:
|
default:
|
||||||
preconditionFailure()
|
preconditionFailure()
|
||||||
}
|
}
|
||||||
@ -134,6 +139,8 @@ public extension EngineMedia {
|
|||||||
return giveaway
|
return giveaway
|
||||||
case let .giveawayResults(giveawayResults):
|
case let .giveawayResults(giveawayResults):
|
||||||
return giveawayResults
|
return giveawayResults
|
||||||
|
case let .paidContent(paidContent):
|
||||||
|
return paidContent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ private final class StarsContextImpl {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var transactions = state.transactions
|
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))
|
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 {
|
private extension StarsContext.State.Transaction {
|
||||||
init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) {
|
init?(apiTransaction: Api.StarsTransaction, transaction: Transaction) {
|
||||||
switch apiTransaction {
|
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
|
let parsedPeer: StarsContext.State.Transaction.Peer
|
||||||
|
var paidMessageId: MessageId?
|
||||||
switch transactionPeer {
|
switch transactionPeer {
|
||||||
case .starsTransactionPeerAppStore:
|
case .starsTransactionPeerAppStore:
|
||||||
parsedPeer = .appStore
|
parsedPeer = .appStore
|
||||||
@ -256,13 +257,19 @@ private extension StarsContext.State.Transaction {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
parsedPeer = .peer(EnginePeer(peer))
|
parsedPeer = .peer(EnginePeer(peer))
|
||||||
|
if let messageId {
|
||||||
|
paidMessageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var flags: Flags = []
|
var flags: Flags = []
|
||||||
if (apiFlags & (1 << 3)) != 0 {
|
if (apiFlags & (1 << 3)) != 0 {
|
||||||
flags.insert(.isRefund)
|
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 isRefund = Flags(rawValue: 1 << 0)
|
||||||
public static let isLocal = Flags(rawValue: 1 << 1)
|
public static let isLocal = Flags(rawValue: 1 << 1)
|
||||||
public static let isPending = Flags(rawValue: 1 << 2)
|
public static let isPending = Flags(rawValue: 1 << 2)
|
||||||
|
public static let isFailed = Flags(rawValue: 1 << 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Peer: Equatable {
|
public enum Peer: Equatable {
|
||||||
@ -301,6 +309,7 @@ public final class StarsContext {
|
|||||||
public let photo: TelegramMediaWebFile?
|
public let photo: TelegramMediaWebFile?
|
||||||
public let transactionDate: Int32?
|
public let transactionDate: Int32?
|
||||||
public let transactionUrl: String?
|
public let transactionUrl: String?
|
||||||
|
public let paidMessageId: MessageId?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
@ -312,7 +321,8 @@ public final class StarsContext {
|
|||||||
description: String?,
|
description: String?,
|
||||||
photo: TelegramMediaWebFile?,
|
photo: TelegramMediaWebFile?,
|
||||||
transactionDate: Int32?,
|
transactionDate: Int32?,
|
||||||
transactionUrl: String?
|
transactionUrl: String?,
|
||||||
|
paidMessageId: MessageId?
|
||||||
) {
|
) {
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.id = id
|
self.id = id
|
||||||
@ -324,6 +334,7 @@ public final class StarsContext {
|
|||||||
self.photo = photo
|
self.photo = photo
|
||||||
self.transactionDate = transactionDate
|
self.transactionDate = transactionDate
|
||||||
self.transactionUrl = transactionUrl
|
self.transactionUrl = transactionUrl
|
||||||
|
self.paidMessageId = paidMessageId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ public enum MessageContentKindKey {
|
|||||||
case invoice
|
case invoice
|
||||||
case story
|
case story
|
||||||
case giveaway
|
case giveaway
|
||||||
|
case paidContent
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MessageContentKind: Equatable {
|
public enum MessageContentKind: Equatable {
|
||||||
@ -54,6 +55,7 @@ public enum MessageContentKind: Equatable {
|
|||||||
case invoice(String)
|
case invoice(String)
|
||||||
case story
|
case story
|
||||||
case giveaway
|
case giveaway
|
||||||
|
case paidContent
|
||||||
|
|
||||||
public func isSemanticallyEqual(to other: MessageContentKind) -> Bool {
|
public func isSemanticallyEqual(to other: MessageContentKind) -> Bool {
|
||||||
switch self {
|
switch self {
|
||||||
@ -189,6 +191,12 @@ public enum MessageContentKind: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case .paidContent:
|
||||||
|
if case .paidContent = other {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,6 +246,8 @@ public enum MessageContentKind: Equatable {
|
|||||||
return .story
|
return .story
|
||||||
case .giveaway:
|
case .giveaway:
|
||||||
return .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)
|
return (NSAttributedString(string: strings.Message_Story), true)
|
||||||
case .giveaway:
|
case .giveaway:
|
||||||
return (NSAttributedString(string: strings.Message_Giveaway), true)
|
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,
|
attributes,
|
||||||
contentMediaValue,
|
contentMediaValue,
|
||||||
nil,
|
nil,
|
||||||
|
nil,
|
||||||
.full,
|
.full,
|
||||||
associatedData.automaticDownloadPeerType,
|
associatedData.automaticDownloadPeerType,
|
||||||
associatedData.automaticDownloadPeerId,
|
associatedData.automaticDownloadPeerId,
|
||||||
|
@ -118,7 +118,7 @@ public enum ChatMessageBubbleContentPosition {
|
|||||||
|
|
||||||
public enum ChatMessageBubblePreparePosition {
|
public enum ChatMessageBubblePreparePosition {
|
||||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||||
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition, index: Int?)
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ChatMessageBubbleContentTapAction {
|
public struct ChatMessageBubbleContentTapAction {
|
||||||
@ -208,6 +208,8 @@ open class ChatMessageBubbleContentNode: ASDisplayNode {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open var index: Int?
|
||||||
|
|
||||||
public weak var itemNode: ChatMessageItemNodeProtocol?
|
public weak var itemNode: ChatMessageItemNodeProtocol?
|
||||||
public weak var bubbleBackgroundNode: ChatMessageBackground?
|
public weak var bubbleBackgroundNode: ChatMessageBackground?
|
||||||
public weak var bubbleBackdropNode: ChatMessageBubbleBackdrop?
|
public weak var bubbleBackdropNode: ChatMessageBubbleBackdrop?
|
||||||
|
@ -78,9 +78,17 @@ import TelegramAnimatedStickerNode
|
|||||||
import LottieMetal
|
import LottieMetal
|
||||||
|
|
||||||
private struct BubbleItemAttributes {
|
private struct BubbleItemAttributes {
|
||||||
|
var index: Int?
|
||||||
var isAttachment: Bool
|
var isAttachment: Bool
|
||||||
var neighborType: ChatMessageBubbleRelativePosition.NeighbourType
|
var neighborType: ChatMessageBubbleRelativePosition.NeighbourType
|
||||||
var neighborSpacing: ChatMessageBubbleRelativePosition.NeighbourSpacing
|
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 {
|
private final class ChatMessageBubbleClippingNode: ASDisplayNode {
|
||||||
@ -123,7 +131,13 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
|||||||
|
|
||||||
var isFile = false
|
var isFile = false
|
||||||
inner: for media in message.media {
|
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 {
|
if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), message.text.isEmpty {
|
||||||
messageWithCaptionToAdd = (message, itemAttributes)
|
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) {
|
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 {
|
for contentNode in self.contentNodes {
|
||||||
if let message = contentNode.item?.message {
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
@ -1388,7 +1402,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
|
|
||||||
private static func beginLayout(
|
private static func beginLayout(
|
||||||
selfReference: Weak<ChatMessageBubbleItemNode>, _ item: ChatMessageItem, _ params: ListViewItemLayoutParams, _ mergedTop: ChatMessageMerge, _ mergedBottom: ChatMessageMerge, _ dateHeaderAtBottom: Bool,
|
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),
|
authorNameLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||||
viaMeasureLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
viaMeasureLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||||
adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
adminBadgeLayout: (TextNodeLayoutArguments) -> (TextNodeLayout, () -> TextNode),
|
||||||
@ -1699,15 +1713,15 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
maximumContentWidth = max(0.0, maximumContentWidth)
|
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 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 {
|
for contentNodeItemValue in contentNodeMessagesAndClasses {
|
||||||
let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes)
|
let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes)
|
||||||
|
|
||||||
var found = false
|
var found = false
|
||||||
for currentNodeItemValue in currentContentClassesPropertiesAndLayouts {
|
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))
|
contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, currentNodeItem.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, currentNodeItem.currentLayout))
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
@ -1715,11 +1729,12 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
let contentNode = (contentNodeItem.type as! ChatMessageBubbleContentNode.Type).init()
|
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()))
|
contentPropertiesAndPrepareLayouts.append((contentNodeItem.message, contentNode.supportsMosaic, contentNodeItem.attributes, contentNodeItem.bubbleAttributes, contentNode.asyncLayoutContent()))
|
||||||
if addedContentNodes == nil {
|
if addedContentNodes == nil {
|
||||||
addedContentNodes = []
|
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
|
let prepareContentPosition: ChatMessageBubblePreparePosition
|
||||||
if let mosaicRange = mosaicRange, mosaicRange.contains(index) {
|
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 {
|
} else {
|
||||||
let refinedBottomPosition: ChatMessageBubbleRelativePosition
|
let refinedBottomPosition: ChatMessageBubbleRelativePosition
|
||||||
if index == contentPropertiesAndPrepareLayouts.count - 1 {
|
if index == contentPropertiesAndPrepareLayouts.count - 1 {
|
||||||
@ -3071,7 +3087,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
replyInfoOriginY: CGFloat,
|
replyInfoOriginY: CGFloat,
|
||||||
removedContentNodeIndices: [Int]?,
|
removedContentNodeIndices: [Int]?,
|
||||||
updatedContentNodeOrder: Bool,
|
updatedContentNodeOrder: Bool,
|
||||||
addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode)]?,
|
addedContentNodes: [(Message, Bool, ChatMessageBubbleContentNode, Int?)]?,
|
||||||
contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)],
|
contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)],
|
||||||
contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, Bool, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)],
|
contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, Bool, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void)],
|
||||||
contentContainerNodeFrames: [(UInt32, CGRect, Bool?, CGFloat)],
|
contentContainerNodeFrames: [(UInt32, CGRect, Bool?, CGFloat)],
|
||||||
@ -3876,7 +3892,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let addedContentNodes = addedContentNodes {
|
if let addedContentNodes = addedContentNodes {
|
||||||
for (contentNodeMessage, isAttachment, contentNode) in addedContentNodes {
|
for (contentNodeMessage, isAttachment, contentNode, _ ) in addedContentNodes {
|
||||||
updatedContentNodes.append(contentNode)
|
updatedContentNodes.append(contentNode)
|
||||||
|
|
||||||
let contextSourceNode: ContextExtractedContentContainingNode
|
let contextSourceNode: ContextExtractedContentContainingNode
|
||||||
@ -3908,18 +3924,17 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
|||||||
|
|
||||||
var sortedContentNodes: [ChatMessageBubbleContentNode] = []
|
var sortedContentNodes: [ChatMessageBubbleContentNode] = []
|
||||||
outer: for contentItemValue in contentNodeMessagesAndClasses {
|
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 {
|
if let addedContentNodes = addedContentNodes {
|
||||||
for (contentNodeMessage, _, contentNode) in addedContentNodes {
|
for (contentNodeMessage, _, contentNode, index) in addedContentNodes {
|
||||||
if type(of: contentNode) == contentItem.type && contentNodeMessage.stableId == contentItem.message.stableId {
|
if type(of: contentNode) == contentItem.type && index == contentItem.attributes.index && contentNodeMessage.stableId == contentItem.message.stableId {
|
||||||
sortedContentNodes.append(contentNode)
|
sortedContentNodes.append(contentNode)
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for contentNode in updatedContentNodes {
|
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)
|
sortedContentNodes.append(contentNode)
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
|
@ -437,6 +437,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
private var message: Message?
|
private var message: Message?
|
||||||
private var attributes: ChatMessageEntryAttributes?
|
private var attributes: ChatMessageEntryAttributes?
|
||||||
private var media: Media?
|
private var media: Media?
|
||||||
|
private var mediaIndex: Int?
|
||||||
private var themeAndStrings: (PresentationTheme, PresentationStrings, String, Bool)?
|
private var themeAndStrings: (PresentationTheme, PresentationStrings, String, Bool)?
|
||||||
private var sizeCalculation: InteractiveMediaNodeSizeCalculation?
|
private var sizeCalculation: InteractiveMediaNodeSizeCalculation?
|
||||||
private var wideLayout: Bool?
|
private var wideLayout: Bool?
|
||||||
@ -719,6 +720,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
} else {
|
} else {
|
||||||
if let invoice = self.media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
if let invoice = self.media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||||
self.activateLocalContent(.default)
|
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) {
|
} 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 {
|
if case let .item(item) = storyItem, let mediaValue = item.media {
|
||||||
let _ = mediaValue
|
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 currentMessage = self.message
|
||||||
let currentMedia = self.media
|
let currentMedia = self.media
|
||||||
let imageLayout = self.imageNode.asyncLayout()
|
let imageLayout = self.imageNode.asyncLayout()
|
||||||
@ -746,7 +749,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
let currentAutomaticDownload = self.automaticDownload
|
let currentAutomaticDownload = self.automaticDownload
|
||||||
let currentAutomaticPlayback = self.automaticPlayback
|
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
|
let _ = peerType
|
||||||
|
|
||||||
var nativeSize: CGSize
|
var nativeSize: CGSize
|
||||||
@ -845,8 +848,18 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
case .color, .gradient, .emoticon:
|
case .color, .gradient, .emoticon:
|
||||||
unboundSize = CGSize(width: 128.0, height: 128.0)
|
unboundSize = CGSize(width: 128.0, height: 128.0)
|
||||||
}
|
}
|
||||||
} else if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
|
} else {
|
||||||
switch 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(dimensions, _, _):
|
case let .preview(dimensions, _, _):
|
||||||
if let dimensions = 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)))
|
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 {
|
} else {
|
||||||
unboundSize = CGSize(width: 54.0, height: 54.0)
|
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 {
|
switch sizeCalculation {
|
||||||
@ -1090,7 +1104,18 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
|
|
||||||
if mediaUpdated || isSendingUpdated || automaticPlaybackUpdated {
|
if mediaUpdated || isSendingUpdated || automaticPlaybackUpdated {
|
||||||
var media = media
|
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 {
|
switch extendedMedia {
|
||||||
case let .preview(_, immediateThumbnailData, _):
|
case let .preview(_, immediateThumbnailData, _):
|
||||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
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
|
var isExtendedMedia = false
|
||||||
if statusUpdated {
|
if statusUpdated {
|
||||||
var media = media
|
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
|
isExtendedMedia = true
|
||||||
media = fullMedia
|
media = fullMedia
|
||||||
}
|
}
|
||||||
@ -1481,6 +1515,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
strongSelf.message = message
|
strongSelf.message = message
|
||||||
strongSelf.attributes = attributes
|
strongSelf.attributes = attributes
|
||||||
strongSelf.media = media
|
strongSelf.media = media
|
||||||
|
strongSelf.mediaIndex = mediaIndex
|
||||||
strongSelf.wideLayout = wideLayout
|
strongSelf.wideLayout = wideLayout
|
||||||
strongSelf.themeAndStrings = (presentationData.theme.theme, presentationData.strings, dateTimeFormat.decimalSeparator, presentationData.isPreview)
|
strongSelf.themeAndStrings = (presentationData.theme.theme, presentationData.strings, dateTimeFormat.decimalSeparator, presentationData.isPreview)
|
||||||
strongSelf.sizeCalculation = sizeCalculation
|
strongSelf.sizeCalculation = sizeCalculation
|
||||||
@ -1719,7 +1754,16 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
let _ = strongSelf.fetchControls.swap(updatedFetchControls)
|
let _ = strongSelf.fetchControls.swap(updatedFetchControls)
|
||||||
|
|
||||||
var media = media
|
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
|
media = fullMedia
|
||||||
}
|
}
|
||||||
if let storyMedia = media as? TelegramMediaStory, let storyItem = message.associatedStories[storyMedia.storyId]?.get(Stories.StoredItem.self) {
|
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 game: TelegramMediaGame?
|
||||||
var webpage: TelegramMediaWebpage?
|
var webpage: TelegramMediaWebpage?
|
||||||
var invoice: TelegramMediaInvoice?
|
var invoice: TelegramMediaInvoice?
|
||||||
|
var paidContent: TelegramMediaPaidContent?
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let media = media as? TelegramMediaWebpage {
|
if let media = media as? TelegramMediaWebpage {
|
||||||
webpage = media
|
webpage = media
|
||||||
} else if let media = media as? TelegramMediaInvoice {
|
} else if let media = media as? TelegramMediaInvoice {
|
||||||
invoice = media
|
invoice = media
|
||||||
|
} else if let media = media as? TelegramMediaPaidContent {
|
||||||
|
paidContent = media
|
||||||
} else if let media = media as? TelegramMediaGame {
|
} else if let media = media as? TelegramMediaGame {
|
||||||
game = media
|
game = media
|
||||||
} else if let _ = media as? TelegramMediaStory {
|
} else if let _ = media as? TelegramMediaStory {
|
||||||
@ -1836,9 +1883,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
automaticPlayback = false
|
automaticPlayback = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let media = self.media as? TelegramMediaInvoice {
|
|
||||||
invoice = media
|
|
||||||
}
|
|
||||||
|
|
||||||
var progressRequired = false
|
var progressRequired = false
|
||||||
if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media {
|
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)
|
let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator)
|
||||||
|
|
||||||
var media = self.media
|
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
|
media = fullMedia
|
||||||
}
|
}
|
||||||
if let storyMedia = media as? TelegramMediaStory, let storyItem = message.associatedStories[storyMedia.storyId]?.get(Stories.StoredItem.self) {
|
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()
|
badgeNode.removeFromSupernode()
|
||||||
}
|
}
|
||||||
|
|
||||||
var icon: ExtendedMediaOverlayNode.Icon? = .lock
|
var icon: ExtendedMediaOverlayNode.Icon?
|
||||||
var displaySpoiler = false
|
var displaySpoiler = false
|
||||||
if let invoice = invoice, let extendedMedia = invoice.extendedMedia, case .preview = extendedMedia {
|
|
||||||
if invoice.currency == "XTR" {
|
var extendedMedia: TelegramExtendedMedia?
|
||||||
icon = nil
|
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
|
displaySpoiler = true
|
||||||
} else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
|
} 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 {
|
if let paidContent {
|
||||||
viewText = "Unlock for ⭐️\(invoice.totalAmount)"
|
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)
|
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 {
|
} else if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
||||||
@ -2361,12 +2425,12 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
self.extendedMediaOverlayNode?.reveal(animated: true)
|
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()
|
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 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 {
|
if let node = node, let currentAsyncLayout = currentAsyncLayout {
|
||||||
imageNode = node
|
imageNode = node
|
||||||
@ -2376,7 +2440,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
imageLayout = imageNode.asyncLayout()
|
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
|
return (unboundSize, initialWidth, { constrainedSize, automaticPlayback, wideLayout, corners in
|
||||||
let (finalWidth, finalLayout) = continueLayout(constrainedSize, automaticPlayback, wideLayout, corners)
|
let (finalWidth, finalLayout) = continueLayout(constrainedSize, automaticPlayback, wideLayout, corners)
|
||||||
@ -2542,12 +2606,12 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func ignoreTapActionAtPoint(_ point: CGPoint) -> Bool {
|
public func ignoreTapActionAtPoint(_ point: CGPoint) -> Bool {
|
||||||
if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
// if let extendedMediaOverlayNode = self.extendedMediaOverlayNode {
|
||||||
let convertedPoint = self.view.convert(point, to: extendedMediaOverlayNode.view)
|
// let convertedPoint = self.view.convert(point, to: extendedMediaOverlayNode.view)
|
||||||
if extendedMediaOverlayNode.buttonNode.frame.contains(convertedPoint) {
|
// if extendedMediaOverlayNode.buttonNode.frame.contains(convertedPoint) {
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
private var highlightedState: Bool = false
|
private var highlightedState: Bool = false
|
||||||
|
|
||||||
private var media: Media?
|
private var media: Media?
|
||||||
|
private var mediaIndex: Int?
|
||||||
private var automaticPlayback: Bool?
|
private var automaticPlayback: Bool?
|
||||||
|
|
||||||
override public var visibility: ListViewItemNodeVisibility {
|
override public var visibility: ListViewItemNodeVisibility {
|
||||||
@ -97,6 +98,8 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
|
|
||||||
return { item, layoutConstants, preparePosition, selection, constrainedSize, _ in
|
return { item, layoutConstants, preparePosition, selection, constrainedSize, _ in
|
||||||
var selectedMedia: Media?
|
var selectedMedia: Media?
|
||||||
|
var selectedMediaIndex: Int?
|
||||||
|
var extendedMedia: TelegramExtendedMedia?
|
||||||
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
|
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
|
||||||
var automaticPlayback: Bool = false
|
var automaticPlayback: Bool = false
|
||||||
var contentMode: InteractiveMediaNodeContentMode = .aspectFit
|
var contentMode: InteractiveMediaNodeContentMode = .aspectFit
|
||||||
@ -107,15 +110,7 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if selectedMedia == nil {
|
if selectedMedia == nil {
|
||||||
for media in item.message.media {
|
for media in item.message.media {
|
||||||
if let telegramImage = media as? TelegramMediaImage {
|
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
|
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) {
|
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
|
automaticDownload = .full
|
||||||
}
|
}
|
||||||
@ -177,38 +172,50 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
contentMode = .aspectFill
|
contentMode = .aspectFill
|
||||||
} else if let invoice = media as? TelegramMediaInvoice {
|
} else if let invoice = media as? TelegramMediaInvoice {
|
||||||
selectedMedia = invoice
|
selectedMedia = invoice
|
||||||
|
extendedMedia = invoice.extendedMedia
|
||||||
if let extendedMedia = invoice.extendedMedia, case let .full(media) = extendedMedia {
|
}
|
||||||
if let telegramImage = media as? TelegramMediaImage {
|
else if let paidContent = media as? TelegramMediaPaidContent {
|
||||||
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) {
|
selectedMedia = paidContent
|
||||||
automaticDownload = .full
|
if case let .mosaic(_, _, index) = preparePosition, let index {
|
||||||
}
|
extendedMedia = paidContent.extendedMedia[index]
|
||||||
} else if let telegramFile = media as? TelegramMediaFile {
|
selectedMediaIndex = index
|
||||||
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) {
|
} else {
|
||||||
automaticDownload = .full
|
extendedMedia = paidContent.extendedMedia.first
|
||||||
} 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 {
|
let _ = selectedMediaIndex
|
||||||
if case .full = automaticDownload {
|
|
||||||
automaticPlayback = true
|
if let extendedMedia, case let .full(media) = extendedMedia {
|
||||||
} else {
|
if let telegramImage = media as? TelegramMediaImage {
|
||||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
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 (telegramFile.isVideo && !telegramFile.isAnimated) && item.context.sharedContext.energyUsageSettings.autoplayVideo {
|
}
|
||||||
if case .full = automaticDownload {
|
} else if let telegramFile = media as? TelegramMediaFile {
|
||||||
automaticPlayback = true
|
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) {
|
||||||
} else {
|
automaticDownload = .full
|
||||||
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(telegramFile.resource) != nil
|
} else if shouldPredownloadMedia(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, media: telegramFile) {
|
||||||
}
|
automaticDownload = .prefetch
|
||||||
}
|
}
|
||||||
}
|
|
||||||
contentMode = .aspectFill
|
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 forceFullCorners = false
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 7.0, hidesBackground: .emptyWallpaper, forceFullCorners: forceFullCorners, forceAlignment: .none)
|
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 {
|
if let strongSelf = self {
|
||||||
strongSelf.item = item
|
strongSelf.item = item
|
||||||
strongSelf.media = selectedMedia
|
strongSelf.media = selectedMedia
|
||||||
|
strongSelf.mediaIndex = selectedMediaIndex
|
||||||
strongSelf.automaticPlayback = automaticPlayback
|
strongSelf.automaticPlayback = automaticPlayback
|
||||||
|
|
||||||
let imageFrame = CGRect(origin: CGPoint(x: bubbleInsets.left, y: bubbleInsets.top), size: imageSize)
|
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 {
|
if let invoice = currentMedia as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||||
currentMedia = fullMedia
|
currentMedia = fullMedia
|
||||||
}
|
}
|
||||||
|
if let paidContent = currentMedia as? TelegramMediaPaidContent, case let .full(fullMedia) = paidContent.extendedMedia[self.mediaIndex ?? 0] {
|
||||||
|
currentMedia = fullMedia
|
||||||
|
}
|
||||||
if currentMedia.isSemanticallyEqual(to: media) {
|
if currentMedia.isSemanticallyEqual(to: media) {
|
||||||
return self.interactiveImageNode.transitionNode(adjustRect: adjustRect)
|
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 {
|
if let invoice = currentMedia as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||||
currentMedia = fullMedia
|
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 {
|
if let currentMedia = currentMedia, let media = media {
|
||||||
for item in media {
|
for item in media {
|
||||||
if item.isSemanticallyEqual(to: currentMedia) {
|
if item.isSemanticallyEqual(to: currentMedia) {
|
||||||
|
@ -619,7 +619,7 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess
|
|||||||
|
|
||||||
let prepareLayout = messageNode.asyncLayoutContent()
|
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)
|
let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(items[i], layoutConstants, prepareContentPosition, nil, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude), 0.0)
|
||||||
maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth)
|
maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth)
|
||||||
|
@ -430,6 +430,13 @@ final class StarsStatisticsScreenComponent: Component {
|
|||||||
rate: starsState?.usdRate ?? 0.0
|
rate: starsState?.usdRate ?? 0.0
|
||||||
))),
|
))),
|
||||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(StarsOverviewItemComponent(
|
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,
|
theme: environment.theme,
|
||||||
dateTimeFormat: environment.dateTimeFormat,
|
dateTimeFormat: environment.dateTimeFormat,
|
||||||
title: strings.Stars_BotRevenue_Proceeds_Total,
|
title: strings.Stars_BotRevenue_Proceeds_Total,
|
||||||
|
@ -426,6 +426,14 @@ private final class SheetContent: CombinedComponent {
|
|||||||
}
|
}
|
||||||
}, completion: { [weak controller] in
|
}, completion: { [weak controller] in
|
||||||
let presentationData = accountContext.sharedContext.currentPresentationData.with { $0 }
|
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 {
|
if let navigationController = controller?.navigationController {
|
||||||
Queue.mainQueue().after(0.5) {
|
Queue.mainQueue().after(0.5) {
|
||||||
if let lastController = navigationController.viewControllers.last as? ViewController {
|
if let lastController = navigationController.viewControllers.last as? ViewController {
|
||||||
@ -434,7 +442,7 @@ private final class SheetContent: CombinedComponent {
|
|||||||
content: .image(
|
content: .image(
|
||||||
image: UIImage(bundleImageName: "Premium/Stars/StarLarge")!,
|
image: UIImage(bundleImageName: "Premium/Stars/StarLarge")!,
|
||||||
title: presentationData.strings.Stars_Transfer_PurchasedTitle,
|
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,
|
round: false,
|
||||||
undoText: nil
|
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(
|
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
|
.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)
|
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)
|
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)
|
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)
|
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
|
// #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 {
|
switch extendedMedia {
|
||||||
case .preview:
|
case .preview:
|
||||||
if displayVoiceMessageDiscardAlert() {
|
if displayVoiceMessageDiscardAlert() {
|
||||||
@ -2633,7 +2645,36 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
for media in message.media {
|
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()
|
strongSelf.chatDisplayNode.dismissInput()
|
||||||
if let receiptMessageId = invoice.receiptMessageId {
|
if let receiptMessageId = invoice.receiptMessageId {
|
||||||
if invoice.currency == "XTR" {
|
if invoice.currency == "XTR" {
|
||||||
|
@ -2655,6 +2655,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||||||
if invoice.version != TelegramMediaInvoice.lastVersion {
|
if invoice.version != TelegramMediaInvoice.lastVersion {
|
||||||
contentRequiredValidation = true
|
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 {
|
} else if let _ = media as? TelegramMediaStory {
|
||||||
storiesRequiredValidation = true
|
storiesRequiredValidation = true
|
||||||
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, let _ = content.story {
|
} 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
|
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
|
var canAddFactCheck = true
|
||||||
if message.media.contains(where: { $0 is TelegramMediaAction || $0 is TelegramMediaGiveaway }) {
|
if message.media.contains(where: { $0 is TelegramMediaAction || $0 is TelegramMediaGiveaway }) {
|
||||||
canAddFactCheck = false
|
canAddFactCheck = false
|
||||||
@ -2190,6 +2190,8 @@ func chatAvailableMessageActionsImpl(engine: TelegramEngine, accountPeerId: Peer
|
|||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
if let invoice = media as? TelegramMediaInvoice, let _ = invoice.extendedMedia {
|
||||||
isShareProtected = true
|
isShareProtected = true
|
||||||
|
} else if let _ = media as? TelegramMediaPaidContent {
|
||||||
|
isShareProtected = true
|
||||||
} else if let file = media as? TelegramMediaFile, file.isSticker {
|
} else if let file = media as? TelegramMediaFile, file.isSticker {
|
||||||
for case let .Sticker(_, packReference, _) in file.attributes {
|
for case let .Sticker(_, packReference, _) in file.attributes {
|
||||||
if let _ = packReference {
|
if let _ = packReference {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user