Update API

This commit is contained in:
Ilya Laktyushin 2026-03-11 14:37:23 +01:00
parent 33d598cbe7
commit 6c1376169c
30 changed files with 1199 additions and 245 deletions

View file

@ -964,7 +964,7 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
if file.isInstantVideo {
isRound = true
}
if file.isVideo && !file.isAnimated && !file.isLivePhoto {
if file.isVideo && !file.isAnimated {
self.playIcon.isHidden = false
} else {
self.playIcon.isHidden = true

View file

@ -232,22 +232,67 @@ public func galleryItemForEntry(
return nil
}
if let _ = media as? TelegramMediaImage {
return ChatImageGalleryItem(
context: context,
presentationData: presentationData,
message: message,
mediaIndex: entry.mediaIndex,
location: location,
translateToLanguage: translateToLanguage,
peerIsCopyProtected: peerIsCopyProtected,
isSecret: isSecret,
displayInfoOnTop: displayInfoOnTop,
performAction: performAction,
openActionOptions: openActionOptions,
sendSticker: sendSticker,
present: present
)
if let image = media as? TelegramMediaImage {
if let file = image.video {
let captureProtected = message.isCopyProtected() || message.containsSecretMedia || message.minAutoremoveOrClearTimeout == viewOnceTimeout || message.paidContent != nil || peerIsCopyProtected
var originData = GalleryItemOriginData(title: message.effectiveAuthor.flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), timestamp: message.timestamp)
if Namespaces.Message.allNonRegular.contains(message.id.namespace) {
originData = GalleryItemOriginData(title: nil, timestamp: nil)
}
let content = NativeVideoContent(id: .message(message.stableId, file.fileId), userLocation: .peer(message.id.peerId), fileReference: .message(message: MessageReference(message), media: file), imageReference: mediaImage.flatMap({ ImageMediaReference.message(message: MessageReference(message), media: $0) }), streamVideo: .conservative, loopVideo: loopVideos, tempFilePath: tempFilePath, captureProtected: captureProtected, storeAfterDownload: generateStoreAfterDownload?(message, file))
var entities: [MessageTextEntity] = []
for attribute in message.attributes {
if let attribute = attribute as? TextEntitiesMessageAttribute {
entities = attribute.entities
break
}
}
var text = galleryMessageCaptionText(message)
if let translateToLanguage, !text.isEmpty {
for attribute in message.attributes {
if let attribute = attribute as? TranslationMessageAttribute, !attribute.text.isEmpty, attribute.toLang == translateToLanguage {
text = attribute.text
entities = attribute.entities
break
}
}
}
let caption = galleryCaptionStringWithAppliedEntities(context: context, text: text, entities: entities, message: message)
return UniversalVideoGalleryItem(
context: context,
presentationData: presentationData,
content: content,
originData: originData,
indexData: location.flatMap { GalleryItemIndexData(position: Int32($0.index), totalCount: Int32($0.count)) },
contentInfo: .message(message, entry.mediaIndex),
caption: caption,
peerIsCopyProtected: peerIsCopyProtected,
playbackRate: playbackRate,
performAction: performAction,
openActionOptions: openActionOptions,
storeMediaPlaybackState: storeMediaPlaybackState,
present: present
)
} else {
return ChatImageGalleryItem(
context: context,
presentationData: presentationData,
message: message,
mediaIndex: entry.mediaIndex,
location: location,
translateToLanguage: translateToLanguage,
peerIsCopyProtected: peerIsCopyProtected,
isSecret: isSecret,
displayInfoOnTop: displayInfoOnTop,
performAction: performAction,
openActionOptions: openActionOptions,
sendSticker: sendSticker,
present: present
)
}
} else if let file = media as? TelegramMediaFile {
if file.isVideo {
let content: UniversalVideoContent

View file

@ -37,6 +37,7 @@ import ToastComponent
import MultilineTextComponent
import BundleIconComponent
import VideoPlaybackControlsComponent
import PhotoResources
public enum UniversalVideoGalleryItemContentInfo {
case message(Message, Int?)
@ -873,6 +874,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private var moreBarButtonRate: Double = 1.0
private var moreBarButtonRateTimestamp: Double?
private var imageNode: TransformImageNode?
private var videoNode: UniversalVideoNode?
private var videoNodeUserInteractionEnabled: Bool = false
private var videoFramePreview: FramePreview?
@ -881,6 +883,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private let statusButtonNode: HighlightableButtonNode
private let statusNode: RadialStatusNode
private var statusNodeShouldBeHidden = true
private var livePhotoIconNode: ASImageNode?
private let playbackControls = ComponentView<Empty>()
@ -949,6 +952,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private var activeEdgeRateIndicator: ComponentView<Empty>?
private var isAnimatingOut: Bool = false
private var isLivePhoto = false
private var didAutoplayLivePhotoOnce = false
init(context: AccountContext, presentationData: PresentationData, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void, openActionOptions: @escaping (GalleryControllerInteractionTapAction, Message) -> Void, present: @escaping (ViewController, Any?) -> Void) {
self.context = context
@ -1358,6 +1363,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
self.dismissOnOrientationChange = item.landscape
self.isLivePhoto = false
self.didAutoplayLivePhotoOnce = false
var hasLinkedStickers = false
if let content = item.content as? NativeVideoContent {
@ -1376,7 +1383,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let content = item.content as? NativeVideoContent {
isAnimated = content.fileReference.media.isAnimated
self.videoFramePreview = MediaPlayerFramePreview(postbox: item.context.account.postbox, userLocation: content.userLocation, userContentType: .video, fileReference: content.fileReference)
if content.fileReference.media.isLivePhoto {
if case let .message(message, _) = item.contentInfo, let _ = message.media.first(where: { $0 is TelegramMediaImage }) {
self.isLivePhoto = true
disablePlayerControls = true
isAnimated = false
}
@ -1506,7 +1514,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let item = strongSelf.item, let _ = item.content as? PlatformVideoContent {
strongSelf.videoNode?.play()
} else {
strongSelf.videoNode?.playOnceWithSound(playAndRecord: false, seek: seek, actionAtEnd: isAnimated ? .loop : strongSelf.actionAtEnd)
if let videoNode = strongSelf.videoNode, strongSelf.playLivePhotoAutoplayIfNeeded(videoNode: videoNode) {
} else {
strongSelf.videoNode?.playOnceWithSound(playAndRecord: false, seek: seek, actionAtEnd: isAnimated ? .loop : strongSelf.actionAtEnd)
}
}
Queue.mainQueue().after(0.1) {
@ -1810,6 +1821,22 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
self.zoomableContent = (videoSize, videoNode)
if case let .message(message, _) = item.contentInfo, let content = item.content as? NativeVideoContent, let image = message.media.first(where: { $0 is TelegramMediaImage }), let imageReference = content.fileReference.abstract.withUpdatedMedia(image).concrete(TelegramMediaImage.self) {
let imageNode = TransformImageNode()
imageNode.alpha = 0.0
imageNode.isUserInteractionEnabled = false
imageNode.setSignal(chatMessagePhoto(postbox: context.account.postbox, userLocation: content.userLocation, photoReference: imageReference, synchronousLoad: true, highQuality: true))
imageNode.frame = CGRect(origin: .zero, size: videoSize)
let imageLayout = imageNode.asyncLayout()
let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: videoSize, boundingSize: videoSize, intrinsicInsets: UIEdgeInsets(), resizeMode: .aspectFill, emptyColor: .clear, custom: nil)
let apply = imageLayout(arguments)
apply()
videoNode.addSubnode(imageNode)
self.imageNode = imageNode
}
var hasSettingsButton = false
var barButtonItems: [UIBarButtonItem] = []
@ -1891,7 +1918,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
if let snapshotView = videoNode?.view.snapshotView(afterScreenUpdates: false) {
if strongSelf.isLivePhoto {
if let imageNode = strongSelf.imageNode {
imageNode.alpha = 1.0
imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
} else if let snapshotView = videoNode?.view.snapshotView(afterScreenUpdates: false) {
videoNode?.view.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
@ -1903,7 +1935,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if strongSelf.actionAtEnd == .stop && strongSelf.isCentral == true {
strongSelf.isPlayingPromise.set(false)
strongSelf.isPlaying = false
if !item.isSecret {
if !item.isSecret && !strongSelf.isLivePhoto {
strongSelf.updateControlsVisibility(true)
}
}
@ -1980,6 +2012,25 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
controller.dismissAndNavigateToMessageContext(message: message)
} : nil)))
}
if self.isLivePhoto {
let livePhotoIconNode: ASImageNode
if let current = self.livePhotoIconNode {
livePhotoIconNode = current
} else {
livePhotoIconNode = ASImageNode()
livePhotoIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Editor/LiveOn"), color: .white)
self.addSubnode(livePhotoIconNode)
self.livePhotoIconNode = livePhotoIconNode
}
if let icon = livePhotoIconNode.image {
livePhotoIconNode.frame = CGRect(origin: CGPoint(x: 8.0, y: 8.0 + 169.0), size: icon.size)
}
} else if let livePhotoIconNode = self.livePhotoIconNode {
self.livePhotoIconNode = nil
livePhotoIconNode.removeFromSupernode()
}
}
override func controlsVisibilityUpdated(isVisible: Bool, animated: Bool) {
@ -2046,6 +2097,16 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
return false
}
private func playLivePhotoAutoplayIfNeeded(videoNode: UniversalVideoNode) -> Bool {
guard self.isLivePhoto, !self.didAutoplayLivePhotoOnce else {
return false
}
self.didAutoplayLivePhotoOnce = true
videoNode.alpha = 1.0
videoNode.continuePlayingWithoutSound(actionAtEnd: .stop)
return true
}
override func centralityUpdated(isCentral: Bool) {
super.centralityUpdated(isCentral: isCentral)
@ -2070,7 +2131,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
videoNode.play()
} else if self.shouldAutoplayOnCentrality() {
self.initiallyActivated = true
videoNode.playOnceWithSound(playAndRecord: false, actionAtEnd: self.actionAtEnd)
if self.playLivePhotoAutoplayIfNeeded(videoNode: videoNode) {
} else {
videoNode.playOnceWithSound(playAndRecord: false, actionAtEnd: self.actionAtEnd)
}
videoNode.setBaseRate(self.playbackRate ?? 1.0)
}
@ -2193,7 +2257,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
} else {
self.hideStatusNodeUntilCentrality = false
self.statusButtonNode.isHidden = self.hideStatusNodeUntilCentrality || self.statusNodeShouldBeHidden
videoNode.playOnceWithSound(playAndRecord: false, seek: seek, actionAtEnd: self.actionAtEnd)
if self.playLivePhotoAutoplayIfNeeded(videoNode: videoNode) {
} else {
videoNode.playOnceWithSound(playAndRecord: false, seek: seek, actionAtEnd: self.actionAtEnd)
}
Queue.mainQueue().after(1.0, {
if let item = self.item, item.isSecret, !self.isPlaying {
@ -2229,6 +2296,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
private var actionAtEnd: MediaPlayerPlayOnceWithSoundActionAtEnd {
if self.isLivePhoto {
return .stop
}
if let item = self.item {
if !item.isSecret, let content = item.content as? NativeVideoContent, content.duration <= 30 {
return .loop
@ -2546,13 +2616,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
} else if let interactiveMediaNode = node.0 as? GalleryItemTransitionNode, interactiveMediaNode.isAvailableForGalleryTransition(), videoNode.hasAttachedContext {
self.imageNode?.alpha = 0.0
copyView.removeFromSuperview()
let previousFrame = videoNode.frame
let previousSuperview = videoNode.view.superview
addToTransitionSurface(videoNode.view)
videoNode.view.superview?.bringSubviewToFront(videoNode.view)
if let previousSuperview = previousSuperview {
videoNode.frame = previousSuperview.convert(previousFrame, to: videoNode.view.superview)
transformedSuperFrame = transformedSuperFrame.offsetBy(dx: videoNode.position.x - previousFrame.center.x, dy: videoNode.position.y - previousFrame.center.y)
@ -3906,7 +3978,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
override func hasActiveEdgeAction(edge: ActiveEdge) -> Bool {
if case .right = edge {
if case .middle = edge {
return self.isLivePhoto
} else if case .right = edge {
if let playerStatusValue = self.playerStatusValue, case .playing = playerStatusValue.status {
return true
} else {
@ -3921,7 +3995,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
guard let videoNode = self.videoNode else {
return
}
if let edge, case .right = edge {
if let edge, case .middle = edge {
print()
} else if let edge, case .right = edge {
let effectiveRate: Double
if let current = self.activeEdgeRateState {
effectiveRate = min(4.0, current.initialRate + 1.0)

View file

@ -131,7 +131,7 @@ private enum LegacyAssetVideoData {
}
private enum LegacyAssetItem {
case image(data: LegacyAssetImageData, thumbnail: UIImage?, caption: NSAttributedString?, stickers: [FileMediaReference])
case image(data: LegacyAssetImageData, thumbnail: UIImage?, caption: NSAttributedString?, stickers: [FileMediaReference], video: LegacyAssetVideoData?)
case file(data: LegacyAssetImageData, thumbnail: UIImage?, mimeType: String, name: String, caption: NSAttributedString?)
case video(data: LegacyAssetVideoData, thumbnail: UIImage?, cover: UIImage?, adjustments: TGVideoEditAdjustments?, caption: NSAttributedString?, asFile: Bool, asAnimation: Bool, stickers: [FileMediaReference], isLivePhoto: Bool)
}
@ -186,7 +186,7 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: 4.0), thumbnail: thumbnail, cover: cover, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: false, asAnimation: true, stickers: stickers, isLivePhoto: false), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
}
} else {
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: stickers), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, forceHd: forceHd, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .image(image), thumbnail: thumbnail, caption: caption, stickers: stickers, video: nil), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, forceHd: forceHd, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
}
return result
} else if (dict["type"] as! NSString) == "cloudPhoto" {
@ -209,7 +209,7 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
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 {
let forceHd = (dict["hd"] as? NSNumber)?.boolValue ?? false
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, forceHd: forceHd, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
result["item" as NSString] = LegacyAssetItemWrapper(item: .image(data: .asset(asset.backingAsset), thumbnail: thumbnail, caption: caption, stickers: [], video: nil), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, forceHd: forceHd, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
}
return result
} else if (dict["type"] as! NSString) == "file" {
@ -269,15 +269,35 @@ public func legacyAssetPickerItemGenerator() -> ((Any?, NSAttributedString?, Str
if let value = dict["livePhoto"] as? Bool {
isLivePhoto = value
}
let url: String? = (dict["url"] as? String) ?? (dict["url"] as? URL)?.path
if let url = url, let previewImage = dict["previewImage"] as? UIImage {
let dimensions = previewImage.pixelSize()
let duration = (dict["duration"]! as AnyObject).doubleValue!
var result: [AnyHashable: Any] = [:]
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, cover: cover, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers, isLivePhoto: isLivePhoto), timer: (dict["timer"] as? NSNumber)?.intValue, spoiler: (dict["spoiler"] as? NSNumber)?.boolValue, price: price, groupedId: (dict["groupedId"] as? NSNumber)?.int64Value, uniqueId: uniqueId)
return result
if isLivePhoto, let cover {
var result: [AnyHashable: Any] = [:]
result["item" as NSString] = LegacyAssetItemWrapper(
item: .image(
data: .image(cover),
thumbnail: thumbnail,
caption: caption,
stickers: stickers,
video: .tempFile(path: url, dimensions: dimensions, duration: duration)
),
timer: (dict["timer"] as? NSNumber)?.intValue,
spoiler: (dict["spoiler"] as? NSNumber)?.boolValue,
price: price,
groupedId: (dict["groupedId"] as? NSNumber)?.int64Value,
uniqueId: uniqueId
)
return result
} else {
var result: [AnyHashable: Any] = [:]
result["item" as NSString] = LegacyAssetItemWrapper(item: .video(data: .tempFile(path: url, dimensions: dimensions, duration: duration), thumbnail: thumbnail, cover: cover, adjustments: dict["adjustments"] as? TGVideoEditAdjustments, caption: caption, asFile: asFile, asAnimation: false, stickers: stickers, isLivePhoto: isLivePhoto), 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 nil
@ -391,7 +411,7 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
outer: for item in (anyValues as! NSArray) {
if let item = (item as? NSDictionary)?.object(forKey: "item") as? LegacyAssetItemWrapper {
switch item.item {
case let .image(data, thumbnail, caption, stickers):
case let .image(data, thumbnail, caption, stickers, video):
var representations: [TelegramMediaImageRepresentation] = []
if let thumbnail = thumbnail {
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
@ -436,7 +456,48 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
imageFlags.insert(.hasStickers)
}
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: imageFlags)
var videoFile: TelegramMediaFile?
if let video, case let .tempFile(path, dimensions, duration) = video {
let finalDimensions: CGSize = dimensions
let finalDuration: Double = duration
//let defaultPreset = TGMediaVideoConversionPreset(rawValue: UInt32(UserDefaults.standard.integer(forKey: "TG_preferredVideoPreset_v0")))
let preset: TGMediaVideoConversionPreset = TGMediaVideoConversionPresetCompressedMedium
// if let selectedPreset = adjustments?.preset {
// preset = selectedPreset
// } else if preset == TGMediaVideoConversionPresetCompressedDefault && defaultPreset != TGMediaVideoConversionPresetCompressedDefault {
// preset = defaultPreset
// }
// if !asAnimation {
// finalDimensions = TGMediaVideoConverter.dimensions(for: finalDimensions, adjustments: adjustments, preset: TGMediaVideoConversionPresetCompressedMedium)
// }
let resourceAdjustments: VideoMediaResourceAdjustments? = nil
// if let adjustments = adjustments {
// if adjustments.trimApplied() {
// finalDuration = adjustments.trimEndValue - adjustments.trimStartValue
// }
//
// if let dict = adjustments.dictionary(), let data = try? NSKeyedArchiver.archivedData(withRootObject: dict, requiringSecureCoding: false) {
// let adjustmentsData = MemoryBuffer(data: data)
// let digest = MemoryBuffer(data: adjustmentsData.md5Digest())
// resourceAdjustments = VideoMediaResourceAdjustments(data: adjustmentsData, digest: digest, isStory: false)
// }
// }
let resource = LocalFileVideoMediaResource(randomId: Int64.random(in: Int64.min ... Int64.max), path: path, adjustments: resourceAdjustments)
let estimatedSize = TGMediaVideoConverter.estimatedSize(for: preset, duration: finalDuration, hasAudio: true)
var fileAttributes: [TelegramMediaFileAttribute] = []
fileAttributes.append(.Video(duration: finalDuration, size: PixelDimensions(finalDimensions), flags: [], preloadSize: nil, coverTime: nil, videoCodec: nil))
if estimatedSize > 10 * 1024 * 1024 {
fileAttributes.append(.hintFileIsLarge)
}
videoFile = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], videoCover: nil, immediateThumbnailData: nil, mimeType: "video/mp4", size: nil, attributes: fileAttributes, alternativeRepresentations: [])
imageFlags.insert(.isLivePhoto)
}
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: randomId), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: imageFlags, video: videoFile)
if let timer = item.timer, timer > 0 && (timer <= 60 || timer == viewOnceTimeout) {
attributes.append(AutoremoveTimeoutMessageAttribute(timeout: Int32(timer), countdownBeginTime: nil))
}
@ -840,7 +901,6 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
}
let defaultPreset = TGMediaVideoConversionPreset(rawValue: UInt32(UserDefaults.standard.integer(forKey: "TG_preferredVideoPreset_v0")))
var preset: TGMediaVideoConversionPreset = TGMediaVideoConversionPresetCompressedMedium
if let selectedPreset = adjustments?.preset {
preset = selectedPreset
@ -850,7 +910,6 @@ public func legacyAssetPickerEnqueueMessages(context: AccountContext, account: A
if asAnimation {
preset = TGMediaVideoConversionPresetAnimation
}
if !asAnimation {
finalDimensions = TGMediaVideoConverter.dimensions(for: finalDimensions, adjustments: adjustments, preset: TGMediaVideoConversionPresetCompressedMedium)
}

View file

@ -415,9 +415,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-104578748] = { return Api.InputMedia.parse_inputMediaGeoPoint($0) }
dict[1080028941] = { return Api.InputMedia.parse_inputMediaInvoice($0) }
dict[-1005571194] = { return Api.InputMedia.parse_inputMediaPaidMedia($0) }
dict[-1279654347] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
dict[-475053004] = { return Api.InputMedia.parse_inputMediaPhoto($0) }
dict[-440664550] = { return Api.InputMedia.parse_inputMediaPhotoExternal($0) }
dict[261416433] = { return Api.InputMedia.parse_inputMediaPoll($0) }
dict[-1229194966] = { return Api.InputMedia.parse_inputMediaPoll($0) }
dict[-207018934] = { return Api.InputMedia.parse_inputMediaStakeDice($0) }
dict[-1979852936] = { return Api.InputMedia.parse_inputMediaStory($0) }
dict[-1614454818] = { return Api.InputMedia.parse_inputMediaTodo($0) }
@ -681,7 +681,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-156940077] = { return Api.MessageMedia.parse_messageMediaInvoice($0) }
dict[-1467669359] = { return Api.MessageMedia.parse_messageMediaPaidMedia($0) }
dict[-501814429] = { return Api.MessageMedia.parse_messageMediaPhoto($0) }
dict[1272375192] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
dict[2000637542] = { return Api.MessageMedia.parse_messageMediaPoll($0) }
dict[1758159491] = { return Api.MessageMedia.parse_messageMediaStory($0) }
dict[-1974226924] = { return Api.MessageMedia.parse_messageMediaToDo($0) }
dict[-1618676578] = { return Api.MessageMedia.parse_messageMediaUnsupported($0) }
@ -814,9 +814,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-96535659] = { return Api.PhotoSize.parse_photoSizeProgressive($0) }
dict[-525288402] = { return Api.PhotoSize.parse_photoStrippedSize($0) }
dict[1484026161] = { return Api.Poll.parse_poll($0) }
dict[-15277366] = { return Api.PollAnswer.parse_pollAnswer($0) }
dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) }
dict[2061444128] = { return Api.PollResults.parse_pollResults($0) }
dict[-237102592] = { return Api.PollAnswer.parse_inputPollAnswer($0) }
dict[-779361553] = { return Api.PollAnswer.parse_pollAnswer($0) }
dict[910500618] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) }
dict[-1166298786] = { return Api.PollResults.parse_pollResults($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[512535275] = { return Api.PostAddress.parse_postAddress($0) }
dict[-419066241] = { return Api.PostInteractionCounters.parse_postInteractionCountersMessage($0) }
@ -1160,6 +1161,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1442983757] = { return Api.Update.parse_updateLangPack($0) }
dict[1180041828] = { return Api.Update.parse_updateLangPackTooLong($0) }
dict[1448076945] = { return Api.Update.parse_updateLoginToken($0) }
dict[1216408986] = { return Api.Update.parse_updateManagedBot($0) }
dict[-710666460] = { return Api.Update.parse_updateMessageExtendedMedia($0) }
dict[1318109142] = { return Api.Update.parse_updateMessageID($0) }
dict[-1398708869] = { return Api.Update.parse_updateMessagePoll($0) }
@ -1250,7 +1252,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-117904610] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
dict[829899656] = { return Api.User.parse_user($0) }
dict[-742634630] = { return Api.User.parse_userEmpty($0) }
dict[-1607745218] = { return Api.UserFull.parse_userFull($0) }
dict[-1577103027] = { return Api.UserFull.parse_userFull($0) }
dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) }
dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) }
dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) }
@ -1348,6 +1350,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1284008785] = { return Api.auth.SentCodeType.parse_sentCodeTypeSmsPhrase($0) }
dict[-1542017919] = { return Api.auth.SentCodeType.parse_sentCodeTypeSmsWord($0) }
dict[-391678544] = { return Api.bots.BotInfo.parse_botInfo($0) }
dict[1012971041] = { return Api.bots.ExportedBotToken.parse_exportedBotToken($0) }
dict[428978491] = { return Api.bots.PopularAppBots.parse_popularAppBots($0) }
dict[212278628] = { return Api.bots.PreviewInfo.parse_previewInfo($0) }
dict[-309659827] = { return Api.channels.AdminLogResults.parse_adminLogResults($0) }
@ -2477,6 +2480,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.bots.BotInfo:
_1.serialize(buffer, boxed)
case let _1 as Api.bots.ExportedBotToken:
_1.serialize(buffer, boxed)
case let _1 as Api.bots.PopularAppBots:
_1.serialize(buffer, boxed)
case let _1 as Api.bots.PreviewInfo:

View file

@ -141,13 +141,15 @@ public extension Api {
public var flags: Int32
public var id: Api.InputPhoto
public var ttlSeconds: Int32?
public init(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?) {
public var video: Api.InputDocument?
public init(flags: Int32, id: Api.InputPhoto, ttlSeconds: Int32?, video: Api.InputDocument?) {
self.flags = flags
self.id = id
self.ttlSeconds = ttlSeconds
self.video = video
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("inputMediaPhoto", [("flags", self.flags as Any), ("id", self.id as Any), ("ttlSeconds", self.ttlSeconds as Any)])
return ("inputMediaPhoto", [("flags", self.flags as Any), ("id", self.id as Any), ("ttlSeconds", self.ttlSeconds as Any), ("video", self.video as Any)])
}
}
public class Cons_inputMediaPhotoExternal: TypeConstructorDescription {
@ -167,17 +169,21 @@ public extension Api {
public var flags: Int32
public var poll: Api.Poll
public var correctAnswers: [Buffer]?
public var attachedMedia: Api.InputMedia?
public var solution: String?
public var solutionEntities: [Api.MessageEntity]?
public init(flags: Int32, poll: Api.Poll, correctAnswers: [Buffer]?, solution: String?, solutionEntities: [Api.MessageEntity]?) {
public var solutionMedia: Api.InputMedia?
public init(flags: Int32, poll: Api.Poll, correctAnswers: [Buffer]?, attachedMedia: Api.InputMedia?, solution: String?, solutionEntities: [Api.MessageEntity]?, solutionMedia: Api.InputMedia?) {
self.flags = flags
self.poll = poll
self.correctAnswers = correctAnswers
self.attachedMedia = attachedMedia
self.solution = solution
self.solutionEntities = solutionEntities
self.solutionMedia = solutionMedia
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("inputMediaPoll", [("flags", self.flags as Any), ("poll", self.poll as Any), ("correctAnswers", self.correctAnswers as Any), ("solution", self.solution as Any), ("solutionEntities", self.solutionEntities as Any)])
return ("inputMediaPoll", [("flags", self.flags as Any), ("poll", self.poll as Any), ("correctAnswers", self.correctAnswers as Any), ("attachedMedia", self.attachedMedia as Any), ("solution", self.solution as Any), ("solutionEntities", self.solutionEntities as Any), ("solutionMedia", self.solutionMedia as Any)])
}
}
public class Cons_inputMediaStakeDice: TypeConstructorDescription {
@ -431,13 +437,16 @@ public extension Api {
break
case .inputMediaPhoto(let _data):
if boxed {
buffer.appendInt32(-1279654347)
buffer.appendInt32(-475053004)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.id.serialize(buffer, true)
if Int(_data.flags) & Int(1 << 0) != 0 {
serializeInt32(_data.ttlSeconds!, buffer: buffer, boxed: false)
}
if Int(_data.flags) & Int(1 << 2) != 0 {
_data.video!.serialize(buffer, true)
}
break
case .inputMediaPhotoExternal(let _data):
if boxed {
@ -451,7 +460,7 @@ public extension Api {
break
case .inputMediaPoll(let _data):
if boxed {
buffer.appendInt32(261416433)
buffer.appendInt32(-1229194966)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.poll.serialize(buffer, true)
@ -462,6 +471,9 @@ public extension Api {
serializeBytes(item, buffer: buffer, boxed: false)
}
}
if Int(_data.flags) & Int(1 << 3) != 0 {
_data.attachedMedia!.serialize(buffer, true)
}
if Int(_data.flags) & Int(1 << 1) != 0 {
serializeString(_data.solution!, buffer: buffer, boxed: false)
}
@ -472,6 +484,9 @@ public extension Api {
item.serialize(buffer, true)
}
}
if Int(_data.flags) & Int(1 << 2) != 0 {
_data.solutionMedia!.serialize(buffer, true)
}
break
case .inputMediaStakeDice(let _data):
if boxed {
@ -590,11 +605,11 @@ public extension Api {
case .inputMediaPaidMedia(let _data):
return ("inputMediaPaidMedia", [("flags", _data.flags as Any), ("starsAmount", _data.starsAmount as Any), ("extendedMedia", _data.extendedMedia as Any), ("payload", _data.payload as Any)])
case .inputMediaPhoto(let _data):
return ("inputMediaPhoto", [("flags", _data.flags as Any), ("id", _data.id as Any), ("ttlSeconds", _data.ttlSeconds as Any)])
return ("inputMediaPhoto", [("flags", _data.flags as Any), ("id", _data.id as Any), ("ttlSeconds", _data.ttlSeconds as Any), ("video", _data.video as Any)])
case .inputMediaPhotoExternal(let _data):
return ("inputMediaPhotoExternal", [("flags", _data.flags as Any), ("url", _data.url as Any), ("ttlSeconds", _data.ttlSeconds as Any)])
case .inputMediaPoll(let _data):
return ("inputMediaPoll", [("flags", _data.flags as Any), ("poll", _data.poll as Any), ("correctAnswers", _data.correctAnswers as Any), ("solution", _data.solution as Any), ("solutionEntities", _data.solutionEntities as Any)])
return ("inputMediaPoll", [("flags", _data.flags as Any), ("poll", _data.poll as Any), ("correctAnswers", _data.correctAnswers as Any), ("attachedMedia", _data.attachedMedia as Any), ("solution", _data.solution as Any), ("solutionEntities", _data.solutionEntities as Any), ("solutionMedia", _data.solutionMedia as Any)])
case .inputMediaStakeDice(let _data):
return ("inputMediaStakeDice", [("gameHash", _data.gameHash as Any), ("tonAmount", _data.tonAmount as Any), ("clientSeed", _data.clientSeed as Any)])
case .inputMediaStory(let _data):
@ -861,11 +876,18 @@ public extension Api {
if Int(_1!) & Int(1 << 0) != 0 {
_3 = reader.readInt32()
}
var _4: Api.InputDocument?
if Int(_1!) & Int(1 << 2) != 0 {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.InputDocument
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.InputMedia.inputMediaPhoto(Cons_inputMediaPhoto(flags: _1!, id: _2!, ttlSeconds: _3))
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.InputMedia.inputMediaPhoto(Cons_inputMediaPhoto(flags: _1!, id: _2!, ttlSeconds: _3, video: _4))
}
else {
return nil
@ -903,23 +925,37 @@ public extension Api {
_3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
}
}
var _4: String?
if Int(_1!) & Int(1 << 1) != 0 {
_4 = parseString(reader)
var _4: Api.InputMedia?
if Int(_1!) & Int(1 << 3) != 0 {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.InputMedia
}
}
var _5: [Api.MessageEntity]?
var _5: String?
if Int(_1!) & Int(1 << 1) != 0 {
_5 = parseString(reader)
}
var _6: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 1) != 0 {
if let _ = reader.readInt32() {
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
}
}
var _7: Api.InputMedia?
if Int(_1!) & Int(1 << 2) != 0 {
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.InputMedia
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil
let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputMedia.inputMediaPoll(Cons_inputMediaPoll(flags: _1!, poll: _2!, correctAnswers: _3, solution: _4, solutionEntities: _5))
let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.InputMedia.inputMediaPoll(Cons_inputMediaPoll(flags: _1!, poll: _2!, correctAnswers: _3, attachedMedia: _4, solution: _5, solutionEntities: _6, solutionMedia: _7))
}
else {
return nil

View file

@ -1298,14 +1298,18 @@ public extension Api {
}
}
public class Cons_messageMediaPoll: TypeConstructorDescription {
public var flags: Int32
public var poll: Api.Poll
public var results: Api.PollResults
public init(poll: Api.Poll, results: Api.PollResults) {
public var attachedMedia: Api.MessageMedia?
public init(flags: Int32, poll: Api.Poll, results: Api.PollResults, attachedMedia: Api.MessageMedia?) {
self.flags = flags
self.poll = poll
self.results = results
self.attachedMedia = attachedMedia
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("messageMediaPoll", [("poll", self.poll as Any), ("results", self.results as Any)])
return ("messageMediaPoll", [("flags", self.flags as Any), ("poll", self.poll as Any), ("results", self.results as Any), ("attachedMedia", self.attachedMedia as Any)])
}
}
public class Cons_messageMediaStory: TypeConstructorDescription {
@ -1581,10 +1585,14 @@ public extension Api {
break
case .messageMediaPoll(let _data):
if boxed {
buffer.appendInt32(1272375192)
buffer.appendInt32(2000637542)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.poll.serialize(buffer, true)
_data.results.serialize(buffer, true)
if Int(_data.flags) & Int(1 << 0) != 0 {
_data.attachedMedia!.serialize(buffer, true)
}
break
case .messageMediaStory(let _data):
if boxed {
@ -1671,7 +1679,7 @@ public extension Api {
case .messageMediaPhoto(let _data):
return ("messageMediaPhoto", [("flags", _data.flags as Any), ("photo", _data.photo as Any), ("ttlSeconds", _data.ttlSeconds as Any), ("video", _data.video as Any)])
case .messageMediaPoll(let _data):
return ("messageMediaPoll", [("poll", _data.poll as Any), ("results", _data.results as Any)])
return ("messageMediaPoll", [("flags", _data.flags as Any), ("poll", _data.poll as Any), ("results", _data.results as Any), ("attachedMedia", _data.attachedMedia as Any)])
case .messageMediaStory(let _data):
return ("messageMediaStory", [("flags", _data.flags as Any), ("peer", _data.peer as Any), ("id", _data.id as Any), ("story", _data.story as Any)])
case .messageMediaToDo(let _data):
@ -2021,18 +2029,28 @@ public extension Api {
}
}
public static func parse_messageMediaPoll(_ reader: BufferReader) -> MessageMedia? {
var _1: Api.Poll?
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.Poll?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.Poll
_2 = Api.parse(reader, signature: signature) as? Api.Poll
}
var _2: Api.PollResults?
var _3: Api.PollResults?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.PollResults
_3 = Api.parse(reader, signature: signature) as? Api.PollResults
}
var _4: Api.MessageMedia?
if Int(_1!) & Int(1 << 0) != 0 {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.MessageMedia
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageMedia.messageMediaPoll(Cons_messageMediaPoll(poll: _1!, results: _2!))
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.MessageMedia.messageMediaPoll(Cons_messageMediaPoll(flags: _1!, poll: _2!, results: _3!, attachedMedia: _4))
}
else {
return nil

View file

@ -776,50 +776,123 @@ public extension Api {
}
}
public extension Api {
enum PollAnswer: TypeConstructorDescription {
public class Cons_pollAnswer: TypeConstructorDescription {
indirect enum PollAnswer: TypeConstructorDescription {
public class Cons_inputPollAnswer: TypeConstructorDescription {
public var flags: Int32
public var text: Api.TextWithEntities
public var option: Buffer
public init(text: Api.TextWithEntities, option: Buffer) {
public var media: Api.InputMedia?
public init(flags: Int32, text: Api.TextWithEntities, option: Buffer, media: Api.InputMedia?) {
self.flags = flags
self.text = text
self.option = option
self.media = media
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("pollAnswer", [("text", self.text as Any), ("option", self.option as Any)])
return ("inputPollAnswer", [("flags", self.flags as Any), ("text", self.text as Any), ("option", self.option as Any), ("media", self.media as Any)])
}
}
public class Cons_pollAnswer: TypeConstructorDescription {
public var flags: Int32
public var text: Api.TextWithEntities
public var option: Buffer
public var media: Api.MessageMedia?
public init(flags: Int32, text: Api.TextWithEntities, option: Buffer, media: Api.MessageMedia?) {
self.flags = flags
self.text = text
self.option = option
self.media = media
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("pollAnswer", [("flags", self.flags as Any), ("text", self.text as Any), ("option", self.option as Any), ("media", self.media as Any)])
}
}
case inputPollAnswer(Cons_inputPollAnswer)
case pollAnswer(Cons_pollAnswer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .pollAnswer(let _data):
case .inputPollAnswer(let _data):
if boxed {
buffer.appendInt32(-15277366)
buffer.appendInt32(-237102592)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.text.serialize(buffer, true)
serializeBytes(_data.option, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 0) != 0 {
_data.media!.serialize(buffer, true)
}
break
case .pollAnswer(let _data):
if boxed {
buffer.appendInt32(-779361553)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.text.serialize(buffer, true)
serializeBytes(_data.option, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 0) != 0 {
_data.media!.serialize(buffer, true)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .inputPollAnswer(let _data):
return ("inputPollAnswer", [("flags", _data.flags as Any), ("text", _data.text as Any), ("option", _data.option as Any), ("media", _data.media as Any)])
case .pollAnswer(let _data):
return ("pollAnswer", [("text", _data.text as Any), ("option", _data.option as Any)])
return ("pollAnswer", [("flags", _data.flags as Any), ("text", _data.text as Any), ("option", _data.option as Any), ("media", _data.media as Any)])
}
}
public static func parse_pollAnswer(_ reader: BufferReader) -> PollAnswer? {
var _1: Api.TextWithEntities?
public static func parse_inputPollAnswer(_ reader: BufferReader) -> PollAnswer? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.TextWithEntities?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
_2 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
}
var _3: Buffer?
_3 = parseBytes(reader)
var _4: Api.InputMedia?
if Int(_1!) & Int(1 << 0) != 0 {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.InputMedia
}
}
var _2: Buffer?
_2 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.PollAnswer.pollAnswer(Cons_pollAnswer(text: _1!, option: _2!))
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PollAnswer.inputPollAnswer(Cons_inputPollAnswer(flags: _1!, text: _2!, option: _3!, media: _4))
}
else {
return nil
}
}
public static func parse_pollAnswer(_ reader: BufferReader) -> PollAnswer? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.TextWithEntities?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
}
var _3: Buffer?
_3 = parseBytes(reader)
var _4: Api.MessageMedia?
if Int(_1!) & Int(1 << 0) != 0 {
if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.MessageMedia
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PollAnswer.pollAnswer(Cons_pollAnswer(flags: _1!, text: _2!, option: _3!, media: _4))
}
else {
return nil
@ -832,14 +905,16 @@ public extension Api {
public class Cons_pollAnswerVoters: TypeConstructorDescription {
public var flags: Int32
public var option: Buffer
public var voters: Int32
public init(flags: Int32, option: Buffer, voters: Int32) {
public var voters: Int32?
public var recentVoters: [Api.Peer]?
public init(flags: Int32, option: Buffer, voters: Int32?, recentVoters: [Api.Peer]?) {
self.flags = flags
self.option = option
self.voters = voters
self.recentVoters = recentVoters
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("pollAnswerVoters", [("flags", self.flags as Any), ("option", self.option as Any), ("voters", self.voters as Any)])
return ("pollAnswerVoters", [("flags", self.flags as Any), ("option", self.option as Any), ("voters", self.voters as Any), ("recentVoters", self.recentVoters as Any)])
}
}
case pollAnswerVoters(Cons_pollAnswerVoters)
@ -848,11 +923,20 @@ public extension Api {
switch self {
case .pollAnswerVoters(let _data):
if boxed {
buffer.appendInt32(997055186)
buffer.appendInt32(910500618)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeBytes(_data.option, buffer: buffer, boxed: false)
serializeInt32(_data.voters, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 2) != 0 {
serializeInt32(_data.voters!, buffer: buffer, boxed: false)
}
if Int(_data.flags) & Int(1 << 2) != 0 {
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(_data.recentVoters!.count))
for item in _data.recentVoters! {
item.serialize(buffer, true)
}
}
break
}
}
@ -860,7 +944,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .pollAnswerVoters(let _data):
return ("pollAnswerVoters", [("flags", _data.flags as Any), ("option", _data.option as Any), ("voters", _data.voters as Any)])
return ("pollAnswerVoters", [("flags", _data.flags as Any), ("option", _data.option as Any), ("voters", _data.voters as Any), ("recentVoters", _data.recentVoters as Any)])
}
}
@ -870,12 +954,21 @@ public extension Api {
var _2: Buffer?
_2 = parseBytes(reader)
var _3: Int32?
_3 = reader.readInt32()
if Int(_1!) & Int(1 << 2) != 0 {
_3 = reader.readInt32()
}
var _4: [Api.Peer]?
if Int(_1!) & Int(1 << 2) != 0 {
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self)
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.PollAnswerVoters.pollAnswerVoters(Cons_pollAnswerVoters(flags: _1!, option: _2!, voters: _3!))
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.PollAnswerVoters.pollAnswerVoters(Cons_pollAnswerVoters(flags: _1!, option: _2!, voters: _3, recentVoters: _4))
}
else {
return nil
@ -884,7 +977,7 @@ public extension Api {
}
}
public extension Api {
enum PollResults: TypeConstructorDescription {
indirect enum PollResults: TypeConstructorDescription {
public class Cons_pollResults: TypeConstructorDescription {
public var flags: Int32
public var results: [Api.PollAnswerVoters]?
@ -892,16 +985,18 @@ public extension Api {
public var recentVoters: [Api.Peer]?
public var solution: String?
public var solutionEntities: [Api.MessageEntity]?
public init(flags: Int32, results: [Api.PollAnswerVoters]?, totalVoters: Int32?, recentVoters: [Api.Peer]?, solution: String?, solutionEntities: [Api.MessageEntity]?) {
public var solutionMedia: Api.MessageMedia?
public init(flags: Int32, results: [Api.PollAnswerVoters]?, totalVoters: Int32?, recentVoters: [Api.Peer]?, solution: String?, solutionEntities: [Api.MessageEntity]?, solutionMedia: Api.MessageMedia?) {
self.flags = flags
self.results = results
self.totalVoters = totalVoters
self.recentVoters = recentVoters
self.solution = solution
self.solutionEntities = solutionEntities
self.solutionMedia = solutionMedia
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("pollResults", [("flags", self.flags as Any), ("results", self.results as Any), ("totalVoters", self.totalVoters as Any), ("recentVoters", self.recentVoters as Any), ("solution", self.solution as Any), ("solutionEntities", self.solutionEntities as Any)])
return ("pollResults", [("flags", self.flags as Any), ("results", self.results as Any), ("totalVoters", self.totalVoters as Any), ("recentVoters", self.recentVoters as Any), ("solution", self.solution as Any), ("solutionEntities", self.solutionEntities as Any), ("solutionMedia", self.solutionMedia as Any)])
}
}
case pollResults(Cons_pollResults)
@ -910,7 +1005,7 @@ public extension Api {
switch self {
case .pollResults(let _data):
if boxed {
buffer.appendInt32(2061444128)
buffer.appendInt32(-1166298786)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
if Int(_data.flags) & Int(1 << 1) != 0 {
@ -940,6 +1035,9 @@ public extension Api {
item.serialize(buffer, true)
}
}
if Int(_data.flags) & Int(1 << 5) != 0 {
_data.solutionMedia!.serialize(buffer, true)
}
break
}
}
@ -947,7 +1045,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .pollResults(let _data):
return ("pollResults", [("flags", _data.flags as Any), ("results", _data.results as Any), ("totalVoters", _data.totalVoters as Any), ("recentVoters", _data.recentVoters as Any), ("solution", _data.solution as Any), ("solutionEntities", _data.solutionEntities as Any)])
return ("pollResults", [("flags", _data.flags as Any), ("results", _data.results as Any), ("totalVoters", _data.totalVoters as Any), ("recentVoters", _data.recentVoters as Any), ("solution", _data.solution as Any), ("solutionEntities", _data.solutionEntities as Any), ("solutionMedia", _data.solutionMedia as Any)])
}
}
@ -980,14 +1078,21 @@ public extension Api {
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
}
}
var _7: Api.MessageMedia?
if Int(_1!) & Int(1 << 5) != 0 {
if let signature = reader.readInt32() {
_7 = Api.parse(reader, signature: signature) as? Api.MessageMedia
}
}
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 1) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 3) == 0) || _4 != nil
let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
return Api.PollResults.pollResults(Cons_pollResults(flags: _1!, results: _2, totalVoters: _3, recentVoters: _4, solution: _5, solutionEntities: _6))
let _c7 = (Int(_1!) & Int(1 << 5) == 0) || _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.PollResults.pollResults(Cons_pollResults(flags: _1!, results: _2, totalVoters: _3, recentVoters: _4, solution: _5, solutionEntities: _6, solutionMedia: _7))
}
else {
return nil

View file

@ -1020,6 +1020,19 @@ public extension Api {
return ("updateLangPackTooLong", [("langCode", self.langCode as Any)])
}
}
public class Cons_updateManagedBot: TypeConstructorDescription {
public var userId: Int64
public var botId: Int64
public var qts: Int32
public init(userId: Int64, botId: Int64, qts: Int32) {
self.userId = userId
self.botId = botId
self.qts = qts
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("updateManagedBot", [("userId", self.userId as Any), ("botId", self.botId as Any), ("qts", self.qts as Any)])
}
}
public class Cons_updateMessageExtendedMedia: TypeConstructorDescription {
public var peer: Api.Peer
public var msgId: Int32
@ -1937,6 +1950,7 @@ public extension Api {
case updateLangPack(Cons_updateLangPack)
case updateLangPackTooLong(Cons_updateLangPackTooLong)
case updateLoginToken
case updateManagedBot(Cons_updateManagedBot)
case updateMessageExtendedMedia(Cons_updateMessageExtendedMedia)
case updateMessageID(Cons_updateMessageID)
case updateMessagePoll(Cons_updateMessagePoll)
@ -2763,6 +2777,14 @@ public extension Api {
buffer.appendInt32(1448076945)
}
break
case .updateManagedBot(let _data):
if boxed {
buffer.appendInt32(1216408986)
}
serializeInt64(_data.userId, buffer: buffer, boxed: false)
serializeInt64(_data.botId, buffer: buffer, boxed: false)
serializeInt32(_data.qts, buffer: buffer, boxed: false)
break
case .updateMessageExtendedMedia(let _data):
if boxed {
buffer.appendInt32(-710666460)
@ -3591,6 +3613,8 @@ public extension Api {
return ("updateLangPackTooLong", [("langCode", _data.langCode as Any)])
case .updateLoginToken:
return ("updateLoginToken", [])
case .updateManagedBot(let _data):
return ("updateManagedBot", [("userId", _data.userId as Any), ("botId", _data.botId as Any), ("qts", _data.qts as Any)])
case .updateMessageExtendedMedia(let _data):
return ("updateMessageExtendedMedia", [("peer", _data.peer as Any), ("msgId", _data.msgId as Any), ("extendedMedia", _data.extendedMedia as Any)])
case .updateMessageID(let _data):
@ -5269,6 +5293,23 @@ public extension Api {
public static func parse_updateLoginToken(_ reader: BufferReader) -> Update? {
return Api.Update.updateLoginToken
}
public static func parse_updateManagedBot(_ reader: BufferReader) -> Update? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateManagedBot(Cons_updateManagedBot(userId: _1!, botId: _2!, qts: _3!))
}
else {
return nil
}
}
public static func parse_updateMessageExtendedMedia(_ reader: BufferReader) -> Update? {
var _1: Api.Peer?
if let signature = reader.readInt32() {

View file

@ -1071,7 +1071,8 @@ public extension Api {
public var mainTab: Api.ProfileTab?
public var savedMusic: Api.Document?
public var note: Api.TextWithEntities?
public init(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, theme: Api.ChatTheme?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?, starsRating: Api.StarsRating?, starsMyPendingRating: Api.StarsRating?, starsMyPendingRatingDate: Int32?, mainTab: Api.ProfileTab?, savedMusic: Api.Document?, note: Api.TextWithEntities?) {
public var botManagerId: Int64?
public init(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, theme: Api.ChatTheme?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?, starsRating: Api.StarsRating?, starsMyPendingRating: Api.StarsRating?, starsMyPendingRatingDate: Int32?, mainTab: Api.ProfileTab?, savedMusic: Api.Document?, note: Api.TextWithEntities?, botManagerId: Int64?) {
self.flags = flags
self.flags2 = flags2
self.id = id
@ -1111,9 +1112,10 @@ public extension Api {
self.mainTab = mainTab
self.savedMusic = savedMusic
self.note = note
self.botManagerId = botManagerId
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("userFull", [("flags", self.flags as Any), ("flags2", self.flags2 as Any), ("id", self.id as Any), ("about", self.about as Any), ("settings", self.settings as Any), ("personalPhoto", self.personalPhoto as Any), ("profilePhoto", self.profilePhoto as Any), ("fallbackPhoto", self.fallbackPhoto as Any), ("notifySettings", self.notifySettings as Any), ("botInfo", self.botInfo as Any), ("pinnedMsgId", self.pinnedMsgId as Any), ("commonChatsCount", self.commonChatsCount as Any), ("folderId", self.folderId as Any), ("ttlPeriod", self.ttlPeriod as Any), ("theme", self.theme as Any), ("privateForwardName", self.privateForwardName as Any), ("botGroupAdminRights", self.botGroupAdminRights as Any), ("botBroadcastAdminRights", self.botBroadcastAdminRights as Any), ("wallpaper", self.wallpaper as Any), ("stories", self.stories as Any), ("businessWorkHours", self.businessWorkHours as Any), ("businessLocation", self.businessLocation as Any), ("businessGreetingMessage", self.businessGreetingMessage as Any), ("businessAwayMessage", self.businessAwayMessage as Any), ("businessIntro", self.businessIntro as Any), ("birthday", self.birthday as Any), ("personalChannelId", self.personalChannelId as Any), ("personalChannelMessage", self.personalChannelMessage as Any), ("stargiftsCount", self.stargiftsCount as Any), ("starrefProgram", self.starrefProgram as Any), ("botVerification", self.botVerification as Any), ("sendPaidMessagesStars", self.sendPaidMessagesStars as Any), ("disallowedGifts", self.disallowedGifts as Any), ("starsRating", self.starsRating as Any), ("starsMyPendingRating", self.starsMyPendingRating as Any), ("starsMyPendingRatingDate", self.starsMyPendingRatingDate as Any), ("mainTab", self.mainTab as Any), ("savedMusic", self.savedMusic as Any), ("note", self.note as Any)])
return ("userFull", [("flags", self.flags as Any), ("flags2", self.flags2 as Any), ("id", self.id as Any), ("about", self.about as Any), ("settings", self.settings as Any), ("personalPhoto", self.personalPhoto as Any), ("profilePhoto", self.profilePhoto as Any), ("fallbackPhoto", self.fallbackPhoto as Any), ("notifySettings", self.notifySettings as Any), ("botInfo", self.botInfo as Any), ("pinnedMsgId", self.pinnedMsgId as Any), ("commonChatsCount", self.commonChatsCount as Any), ("folderId", self.folderId as Any), ("ttlPeriod", self.ttlPeriod as Any), ("theme", self.theme as Any), ("privateForwardName", self.privateForwardName as Any), ("botGroupAdminRights", self.botGroupAdminRights as Any), ("botBroadcastAdminRights", self.botBroadcastAdminRights as Any), ("wallpaper", self.wallpaper as Any), ("stories", self.stories as Any), ("businessWorkHours", self.businessWorkHours as Any), ("businessLocation", self.businessLocation as Any), ("businessGreetingMessage", self.businessGreetingMessage as Any), ("businessAwayMessage", self.businessAwayMessage as Any), ("businessIntro", self.businessIntro as Any), ("birthday", self.birthday as Any), ("personalChannelId", self.personalChannelId as Any), ("personalChannelMessage", self.personalChannelMessage as Any), ("stargiftsCount", self.stargiftsCount as Any), ("starrefProgram", self.starrefProgram as Any), ("botVerification", self.botVerification as Any), ("sendPaidMessagesStars", self.sendPaidMessagesStars as Any), ("disallowedGifts", self.disallowedGifts as Any), ("starsRating", self.starsRating as Any), ("starsMyPendingRating", self.starsMyPendingRating as Any), ("starsMyPendingRatingDate", self.starsMyPendingRatingDate as Any), ("mainTab", self.mainTab as Any), ("savedMusic", self.savedMusic as Any), ("note", self.note as Any), ("botManagerId", self.botManagerId as Any)])
}
}
case userFull(Cons_userFull)
@ -1122,7 +1124,7 @@ public extension Api {
switch self {
case .userFull(let _data):
if boxed {
buffer.appendInt32(-1607745218)
buffer.appendInt32(-1577103027)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
serializeInt32(_data.flags2, buffer: buffer, boxed: false)
@ -1229,6 +1231,9 @@ public extension Api {
if Int(_data.flags2) & Int(1 << 22) != 0 {
_data.note!.serialize(buffer, true)
}
if Int(_data.flags2) & Int(1 << 23) != 0 {
serializeInt64(_data.botManagerId!, buffer: buffer, boxed: false)
}
break
}
}
@ -1236,7 +1241,7 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .userFull(let _data):
return ("userFull", [("flags", _data.flags as Any), ("flags2", _data.flags2 as Any), ("id", _data.id as Any), ("about", _data.about as Any), ("settings", _data.settings as Any), ("personalPhoto", _data.personalPhoto as Any), ("profilePhoto", _data.profilePhoto as Any), ("fallbackPhoto", _data.fallbackPhoto as Any), ("notifySettings", _data.notifySettings as Any), ("botInfo", _data.botInfo as Any), ("pinnedMsgId", _data.pinnedMsgId as Any), ("commonChatsCount", _data.commonChatsCount as Any), ("folderId", _data.folderId as Any), ("ttlPeriod", _data.ttlPeriod as Any), ("theme", _data.theme as Any), ("privateForwardName", _data.privateForwardName as Any), ("botGroupAdminRights", _data.botGroupAdminRights as Any), ("botBroadcastAdminRights", _data.botBroadcastAdminRights as Any), ("wallpaper", _data.wallpaper as Any), ("stories", _data.stories as Any), ("businessWorkHours", _data.businessWorkHours as Any), ("businessLocation", _data.businessLocation as Any), ("businessGreetingMessage", _data.businessGreetingMessage as Any), ("businessAwayMessage", _data.businessAwayMessage as Any), ("businessIntro", _data.businessIntro as Any), ("birthday", _data.birthday as Any), ("personalChannelId", _data.personalChannelId as Any), ("personalChannelMessage", _data.personalChannelMessage as Any), ("stargiftsCount", _data.stargiftsCount as Any), ("starrefProgram", _data.starrefProgram as Any), ("botVerification", _data.botVerification as Any), ("sendPaidMessagesStars", _data.sendPaidMessagesStars as Any), ("disallowedGifts", _data.disallowedGifts as Any), ("starsRating", _data.starsRating as Any), ("starsMyPendingRating", _data.starsMyPendingRating as Any), ("starsMyPendingRatingDate", _data.starsMyPendingRatingDate as Any), ("mainTab", _data.mainTab as Any), ("savedMusic", _data.savedMusic as Any), ("note", _data.note as Any)])
return ("userFull", [("flags", _data.flags as Any), ("flags2", _data.flags2 as Any), ("id", _data.id as Any), ("about", _data.about as Any), ("settings", _data.settings as Any), ("personalPhoto", _data.personalPhoto as Any), ("profilePhoto", _data.profilePhoto as Any), ("fallbackPhoto", _data.fallbackPhoto as Any), ("notifySettings", _data.notifySettings as Any), ("botInfo", _data.botInfo as Any), ("pinnedMsgId", _data.pinnedMsgId as Any), ("commonChatsCount", _data.commonChatsCount as Any), ("folderId", _data.folderId as Any), ("ttlPeriod", _data.ttlPeriod as Any), ("theme", _data.theme as Any), ("privateForwardName", _data.privateForwardName as Any), ("botGroupAdminRights", _data.botGroupAdminRights as Any), ("botBroadcastAdminRights", _data.botBroadcastAdminRights as Any), ("wallpaper", _data.wallpaper as Any), ("stories", _data.stories as Any), ("businessWorkHours", _data.businessWorkHours as Any), ("businessLocation", _data.businessLocation as Any), ("businessGreetingMessage", _data.businessGreetingMessage as Any), ("businessAwayMessage", _data.businessAwayMessage as Any), ("businessIntro", _data.businessIntro as Any), ("birthday", _data.birthday as Any), ("personalChannelId", _data.personalChannelId as Any), ("personalChannelMessage", _data.personalChannelMessage as Any), ("stargiftsCount", _data.stargiftsCount as Any), ("starrefProgram", _data.starrefProgram as Any), ("botVerification", _data.botVerification as Any), ("sendPaidMessagesStars", _data.sendPaidMessagesStars as Any), ("disallowedGifts", _data.disallowedGifts as Any), ("starsRating", _data.starsRating as Any), ("starsMyPendingRating", _data.starsMyPendingRating as Any), ("starsMyPendingRatingDate", _data.starsMyPendingRatingDate as Any), ("mainTab", _data.mainTab as Any), ("savedMusic", _data.savedMusic as Any), ("note", _data.note as Any), ("botManagerId", _data.botManagerId as Any)])
}
}
@ -1435,6 +1440,10 @@ public extension Api {
_39 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
}
}
var _40: Int64?
if Int(_2!) & Int(1 << 23) != 0 {
_40 = reader.readInt64()
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -1474,8 +1483,9 @@ public extension Api {
let _c37 = (Int(_2!) & Int(1 << 20) == 0) || _37 != nil
let _c38 = (Int(_2!) & Int(1 << 21) == 0) || _38 != nil
let _c39 = (Int(_2!) & Int(1 << 22) == 0) || _39 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 {
return Api.UserFull.userFull(Cons_userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, theme: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedGifts: _33, starsRating: _34, starsMyPendingRating: _35, starsMyPendingRatingDate: _36, mainTab: _37, savedMusic: _38, note: _39))
let _c40 = (Int(_2!) & Int(1 << 23) == 0) || _40 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 && _c40 {
return Api.UserFull.userFull(Cons_userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, theme: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedGifts: _33, starsRating: _34, starsMyPendingRating: _35, starsMyPendingRatingDate: _36, mainTab: _37, savedMusic: _38, note: _39, botManagerId: _40))
}
else {
return nil

View file

@ -54,6 +54,50 @@ public extension Api.bots {
}
}
}
public extension Api.bots {
enum ExportedBotToken: TypeConstructorDescription {
public class Cons_exportedBotToken: TypeConstructorDescription {
public var token: String
public init(token: String) {
self.token = token
}
public func descriptionFields() -> (String, [(String, Any)]) {
return ("exportedBotToken", [("token", self.token as Any)])
}
}
case exportedBotToken(Cons_exportedBotToken)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .exportedBotToken(let _data):
if boxed {
buffer.appendInt32(1012971041)
}
serializeString(_data.token, buffer: buffer, boxed: false)
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .exportedBotToken(let _data):
return ("exportedBotToken", [("token", _data.token as Any)])
}
}
public static func parse_exportedBotToken(_ reader: BufferReader) -> ExportedBotToken? {
var _1: String?
_1 = parseString(reader)
let _c1 = _1 != nil
if _c1 {
return Api.bots.ExportedBotToken.exportedBotToken(Cons_exportedBotToken(token: _1!))
}
else {
return nil
}
}
}
}
public extension Api.bots {
enum PopularAppBots: TypeConstructorDescription {
public class Cons_popularAppBots: TypeConstructorDescription {

View file

@ -2557,6 +2557,38 @@ public extension Api.functions.bots {
})
}
}
public extension Api.functions.bots {
static func checkUsername(username: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-2014174821)
serializeString(username, buffer: buffer, boxed: false)
return (FunctionDescription(name: "bots.checkUsername", parameters: [("username", String(describing: username))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
public extension Api.functions.bots {
static func createBot(name: String, username: String, managerId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.User>) {
let buffer = Buffer()
buffer.appendInt32(-1656313365)
serializeString(name, buffer: buffer, boxed: false)
serializeString(username, buffer: buffer, boxed: false)
managerId.serialize(buffer, true)
return (FunctionDescription(name: "bots.createBot", parameters: [("name", String(describing: name)), ("username", String(describing: username)), ("managerId", String(describing: managerId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.User? in
let reader = BufferReader(buffer)
var result: Api.User?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.User
}
return result
})
}
}
public extension Api.functions.bots {
static func deletePreviewMedia(bot: Api.InputUser, langCode: String, media: [Api.InputMedia]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
@ -2596,6 +2628,22 @@ public extension Api.functions.bots {
})
}
}
public extension Api.functions.bots {
static func exportBotToken(botId: Int64, revoke: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.bots.ExportedBotToken>) {
let buffer = Buffer()
buffer.appendInt32(6533257)
serializeInt64(botId, buffer: buffer, boxed: false)
revoke.serialize(buffer, true)
return (FunctionDescription(name: "bots.exportBotToken", parameters: [("botId", String(describing: botId)), ("revoke", String(describing: revoke))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.bots.ExportedBotToken? in
let reader = BufferReader(buffer)
var result: Api.bots.ExportedBotToken?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.bots.ExportedBotToken
}
return result
})
}
}
public extension Api.functions.bots {
static func getAdminedBots() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.User]>) {
let buffer = Buffer()
@ -5241,6 +5289,23 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func addPollAnswer(peer: Api.InputPeer, msgId: Int32, answer: Api.PollAnswer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(431770477)
peer.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
answer.serialize(buffer, true)
return (FunctionDescription(name: "messages.addPollAnswer", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("answer", String(describing: answer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.messages {
static func appendTodoList(peer: Api.InputPeer, msgId: Int32, list: [Api.TodoItem]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
@ -9500,16 +9565,19 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func summarizeText(flags: Int32, peer: Api.InputPeer, id: Int32, toLang: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.TextWithEntities>) {
static func summarizeText(flags: Int32, peer: Api.InputPeer, id: Int32, toLang: String?, tone: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.TextWithEntities>) {
let buffer = Buffer()
buffer.appendInt32(-1656683294)
buffer.appendInt32(-1413754042)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt32(id, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {
serializeString(toLang!, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "messages.summarizeText", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id)), ("toLang", String(describing: toLang))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.TextWithEntities? in
if Int(flags) & Int(1 << 2) != 0 {
serializeString(tone!, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "messages.summarizeText", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("id", String(describing: id)), ("toLang", String(describing: toLang)), ("tone", String(describing: tone))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.TextWithEntities? in
let reader = BufferReader(buffer)
var result: Api.TextWithEntities?
if let signature = reader.readInt32() {

View file

@ -44,6 +44,9 @@ func telegramMediaImageFromApiPhoto(_ photo: Api.Photo, video: Api.Document? = n
if hasStickers {
imageFlags.insert(.hasStickers)
}
if video != nil {
imageFlags.insert(.isLivePhoto)
}
var videoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
var emojiMarkup: TelegramMediaImage.EmojiMarkup?

View file

@ -18,11 +18,22 @@ extension TelegramMediaPollOption {
}
self.init(text: answerText, entities: answerEntities, opaqueIdentifier: option.makeData())
case let .inputPollAnswer(inputPollAnswerData):
let text = inputPollAnswerData.text
let answerText: String
let answerEntities: [MessageTextEntity]
switch text {
case let .textWithEntities(textWithEntitiesData):
let (text, entities) = (textWithEntitiesData.text, textWithEntitiesData.entities)
answerText = text
answerEntities = messageTextEntitiesFromApiEntities(entities)
}
self.init(text: answerText, entities: answerEntities, opaqueIdentifier: Data())
}
}
var apiOption: Api.PollAnswer {
return .pollAnswer(.init(text: .textWithEntities(.init(text: self.text, entities: apiEntitiesFromMessageTextEntities(self.entities, associatedPeers: SimpleDictionary()))), option: Buffer(data: self.opaqueIdentifier)))
return .pollAnswer(.init(flags: 0, text: .textWithEntities(.init(text: self.text, entities: apiEntitiesFromMessageTextEntities(self.entities, associatedPeers: SimpleDictionary()))), option: Buffer(data: self.opaqueIdentifier), media: nil))
}
}

View file

@ -147,7 +147,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
}
mediaIds.append(id)
if let image = media as? TelegramMediaImage {
signals.append(uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, image: image, messageId: messageId, text: "", attributes: [], autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, auxiliaryMethods: auxiliaryMethods))
signals.append(uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, 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: isGrouped, isPaid: true, passFetchProgress: false, forceNoBigParts: false, peerId: peerId, messageId: messageId, text: "", attributes: [], autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, file: file))
}
@ -191,9 +191,9 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(.inputEncryptedFile(.init(id: resource.fileId, accessHash: resource.accessHash)), resource.decryptedSize, resource.key), reuploadInfo: nil, cacheReferenceKey: nil)))
}
if peerId.namespace != Namespaces.Peer.SecretChat, let reference = image.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: nil, video: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
} else {
return uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, image: image, messageId: messageId, text: text, attributes: attributes, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, auxiliaryMethods: auxiliaryMethods)
return uploadedMediaImageContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, image: image, messageId: messageId, text: text, attributes: attributes, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, auxiliaryMethods: auxiliaryMethods)
}
} else if let file = media as? TelegramMediaFile {
if let resource = file.resource as? CloudDocumentMediaResource {
@ -337,7 +337,7 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
mappedSolutionEntities = apiTextAttributeEntities(TextEntitiesMessageAttribute(entities: solution.entities), associatedPeers: SimpleDictionary())
pollMediaFlags |= 1 << 1
}
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities))
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil))
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil, cacheReferenceKey: nil)))
} else if let todo = media as? TelegramMediaTodo {
var flags: Int32 = 0
@ -498,30 +498,17 @@ private func maybeCacheUploadedResource(postbox: Postbox, key: CachedSentMediaRe
}
}
private func uploadedMediaImageContent(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, image: TelegramMediaImage, messageId: MessageId?, text: String, attributes: [MessageAttribute], autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> {
private func uploadedMediaImageContent(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, image: TelegramMediaImage, messageId: MessageId?, text: String, attributes: [MessageAttribute], autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, auxiliaryMethods: AccountAuxiliaryMethods) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> {
guard let largestRepresentation = largestImageRepresentation(image.representations) else {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil, cacheReferenceKey: nil)))
}
/*#if DEBUG
if "".isEmpty {
return auxiliaryMethods.backgroundUpload(postbox, network, largestRepresentation.resource)
|> castError(PendingMessageUploadError.self)
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
if let result = result {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(
content: .text(result),
reuploadInfo: nil,
cacheReferenceKey: nil
)))
} else {
return .fail(.generic)
}
let predownloadedResource: Signal<PredownloadedResource, PendingMessageUploadError>
if image.video != nil {
predownloadedResource = .single(.none)
} else {
predownloadedResource = maybePredownloadedImageResource(postbox: postbox, peerId: peerId, resource: largestRepresentation.resource, forceRefresh: forceReupload)
}
}
#endif*/
let predownloadedResource: Signal<PredownloadedResource, PendingMessageUploadError> = maybePredownloadedImageResource(postbox: postbox, peerId: peerId, resource: largestRepresentation.resource, forceRefresh: forceReupload)
return predownloadedResource
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
var referenceKey: CachedSentMediaReferenceKey?
@ -542,7 +529,7 @@ if "".isEmpty {
}
return .single(.progress(PendingMessageUploadedContentProgress(progress: 1.0)))
|> then(
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(.init(flags: flags, id: .inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: ttlSeconds)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(.init(flags: flags, id: .inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: ttlSeconds, video: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
)
}
referenceKey = key
@ -644,13 +631,39 @@ if "".isEmpty {
} else {
imageReference = .standalone(media: transformedImage)
}
return multipartUpload(network: network, postbox: postbox, source: .resource(imageReference.resourceReference(largestRepresentation.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image, userContentType: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
let photoUpload = multipartUpload(network: network, postbox: postbox, source: .resource(imageReference.resourceReference(largestRepresentation.resource)), encrypt: peerId.namespace == Namespaces.Peer.SecretChat, tag: TelegramMediaResourceFetchTag(statsCategory: .image, userContentType: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: false)
|> mapError { _ -> PendingMessageUploadError in return .generic }
|> mapToSignal { next -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
let photoVideoUpload: Signal<UploadedMediaPhotoVideoResult?, PendingMessageUploadError>
if peerId.namespace != Namespaces.Peer.SecretChat, let video = transformedImage.video ?? image.video {
photoVideoUpload = uploadedMediaPhotoVideoContent(network: network, postbox: postbox, messageMediaPreuploadManager: messageMediaPreuploadManager, peerId: peerId, file: video)
|> map(Optional.init)
} else {
photoVideoUpload = .single(nil)
}
return combineLatest(photoUpload, photoVideoUpload)
|> mapToSignal { next, photoVideo -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
switch next {
case let .progress(progress):
return .single(.progress(PendingMessageUploadedContentProgress(progress: progress)))
var combinedProgress = progress
if let photoVideo {
if case let .progress(photoVideoProgress) = photoVideo {
combinedProgress = (progress + photoVideoProgress) * 0.5
} else {
combinedProgress = (progress + 1.0) * 0.5
}
}
return .single(.progress(PendingMessageUploadedContentProgress(progress: combinedProgress)))
case let .inputFile(file):
var video: Api.InputDocument?
if let photoVideo {
switch photoVideo {
case let .progress(progress):
return .single(.progress(PendingMessageUploadedContentProgress(progress: (1.0 + progress) * 0.5)))
case let .inputDocument(inputDocument):
video = inputDocument
}
}
var flags: Int32 = 0
var ttlSeconds: Int32?
if let autoclearMessageAttribute = autoclearMessageAttribute {
@ -676,42 +689,46 @@ if "".isEmpty {
hasSpoiler = true
}
}
if let _ = photoVideo {
flags |= 1 << 3
}
return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapError { _ -> PendingMessageUploadError in }
|> mapToSignal { inputPeer -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
if let inputPeer = inputPeer {
if autoclearMessageAttribute != nil {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
if autoclearMessageAttribute != nil || photoVideo != nil {
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: video)), text), reuploadInfo: nil, cacheReferenceKey: nil)))
}
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: nil))))
return network.request(Api.functions.messages.uploadMedia(flags: 0, businessConnectionId: nil, peer: inputPeer, media: Api.InputMedia.inputMediaUploadedPhoto(.init(flags: flags, file: file, stickers: stickers, ttlSeconds: ttlSeconds, video: video))))
|> mapError { _ -> PendingMessageUploadError in return .generic }
|> mapToSignal { result -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError> in
switch result {
case let .messageMediaPhoto(messageMediaPhotoData):
let photo = messageMediaPhotoData.photo
if let photo = photo, let mediaImage = telegramMediaImageFromApiPhoto(photo), let reference = mediaImage.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference {
var flags: Int32 = 0
var ttlSeconds: Int32?
if let autoclearMessageAttribute = autoclearMessageAttribute {
flags |= 1 << 0
ttlSeconds = autoclearMessageAttribute.timeout
}
if hasSpoiler {
flags |= 1 << 1
}
let result: PendingMessageUploadedContentResult = .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(.init(flags: flags, id: .inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: ttlSeconds)), text), reuploadInfo: nil, cacheReferenceKey: nil))
if let _ = ttlSeconds {
return .single(result)
} else {
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: result, media: mediaImage)
}
case let .messageMediaPhoto(messageMediaPhotoData):
let photo = messageMediaPhotoData.photo
if let photo = photo, let mediaImage = telegramMediaImageFromApiPhoto(photo, video: messageMediaPhotoData.video), let reference = mediaImage.reference, case let .cloud(id, accessHash, maybeFileReference) = reference, let fileReference = maybeFileReference {
var flags: Int32 = 0
var ttlSeconds: Int32?
if let autoclearMessageAttribute = autoclearMessageAttribute {
flags |= 1 << 0
ttlSeconds = autoclearMessageAttribute.timeout
}
default:
break
if hasSpoiler {
flags |= 1 << 1
}
let result: PendingMessageUploadedContentResult = .content(PendingMessageUploadedContentAndReuploadInfo(content: .media(.inputMediaPhoto(.init(flags: flags, id: .inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: ttlSeconds, video: nil)), text), reuploadInfo: nil, cacheReferenceKey: nil))
if let _ = ttlSeconds {
return .single(result)
} else {
return maybeCacheUploadedResource(postbox: postbox, key: referenceKey, result: result, media: mediaImage)
}
}
default:
break
}
return .fail(.generic)
}
@ -821,11 +838,116 @@ private enum UploadedMediaThumbnailResult {
case none
}
private enum UploadedMediaPhotoVideoResult {
case progress(Float)
case inputDocument(Api.InputDocument)
}
private enum UploadedMediaFileAndThumbnail {
case pending
case done(TelegramMediaFile, UploadedMediaThumbnailResult, UploadedMediaThumbnailResult)
}
private func uploadedMediaPhotoVideoContent(network: Network, postbox: Postbox, messageMediaPreuploadManager: MessageMediaPreuploadManager, peerId: PeerId, file: TelegramMediaFile) -> Signal<UploadedMediaPhotoVideoResult, PendingMessageUploadError> {
var hintFileIsLarge = false
var hintSize: Int64?
if let size = file.size {
hintSize = size
} else if let resource = file.resource as? LocalFileReferenceMediaResource, let size = resource.size {
hintSize = size
}
loop: for attribute in file.attributes {
switch attribute {
case .hintFileIsLarge:
hintFileIsLarge = true
break loop
default:
break
}
}
let fileReference: AnyMediaReference
if let partialReference = file.partialReference {
fileReference = partialReference.mediaReference(file)
} else {
fileReference = .standalone(media: file)
}
return messageMediaPreuploadManager.upload(
network: network,
postbox: postbox,
source: .resource(fileReference.resourceReference(file.resource)),
encrypt: false,
tag: TelegramMediaResourceFetchTag(statsCategory: .video, userContentType: .video),
hintFileSize: hintSize,
hintFileIsLarge: hintFileIsLarge,
forceNoBigParts: false
)
|> mapError { _ -> PendingMessageUploadError in
return .generic
}
|> mapToSignal { result -> Signal<UploadedMediaPhotoVideoResult, PendingMessageUploadError> in
switch result {
case let .progress(progress):
return .single(.progress(progress))
case let .inputFile(inputFile):
return postbox.transaction { transaction -> Api.InputPeer? in
return transaction.getPeer(peerId).flatMap(apiInputPeer)
}
|> mapError { _ -> PendingMessageUploadError in
}
|> mapToSignal { inputPeer -> Signal<UploadedMediaPhotoVideoResult, PendingMessageUploadError> in
guard let inputPeer else {
return .fail(.generic)
}
return network.request(Api.functions.messages.uploadMedia(
flags: 0,
businessConnectionId: nil,
peer: inputPeer,
media: .inputMediaUploadedDocument(.init(
flags: 0,
file: inputFile,
thumb: nil,
mimeType: file.mimeType,
attributes: inputDocumentAttributesFromFileAttributes(file.attributes),
stickers: nil,
videoCover: nil,
videoTimestamp: nil,
ttlSeconds: nil
))
))
|> mapError { _ -> PendingMessageUploadError in
return .generic
}
|> mapToSignal { result -> Signal<UploadedMediaPhotoVideoResult, PendingMessageUploadError> in
switch result {
case let .messageMediaDocument(messageMediaDocumentData):
let (document, altDocuments) = (messageMediaDocumentData.document, messageMediaDocumentData.altDocuments)
if let document = document,
let mediaFile = telegramMediaFileFromApiDocument(document, altDocuments: altDocuments),
let resource = mediaFile.resource as? CloudDocumentMediaResource,
let fileReference = resource.fileReference {
return .single(.inputDocument(.inputDocument(.init(
id: resource.fileId,
accessHash: resource.accessHash,
fileReference: Buffer(data: fileReference)
))))
} else {
return .fail(.generic)
}
default:
return .fail(.generic)
}
}
}
case .inputSecretFile:
return .fail(.generic)
}
}
}
private func uploadedThumbnail(network: Network, postbox: Postbox, resourceReference: MediaResourceReference, forceNoBigParts: Bool = false) -> Signal<Api.InputFile?, PendingMessageUploadError> {
return multipartUpload(network: network, postbox: postbox, source: .resource(resourceReference), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image, userContentType: .image), hintFileSize: nil, hintFileIsLarge: false, forceNoBigParts: forceNoBigParts)
|> mapError { _ -> PendingMessageUploadError in return .generic }

View file

@ -1059,11 +1059,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable {
}
return false
}
public var isLivePhoto: Bool {
return false
}
public var preloadSize: Int32? {
for attribute in self.attributes {
if case .Video(_, _, _, let preloadSize, _, _) = attribute {

View file

@ -28,10 +28,10 @@ public struct TelegramMediaPollOption: Equatable, PostboxCoding {
public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding {
public let selected: Bool
public let opaqueIdentifier: Data
public let count: Int32
public let count: Int32?
public let isCorrect: Bool
public init(selected: Bool, opaqueIdentifier: Data, count: Int32, isCorrect: Bool) {
public init(selected: Bool, opaqueIdentifier: Data, count: Int32?, isCorrect: Bool) {
self.selected = selected
self.opaqueIdentifier = opaqueIdentifier
self.count = count
@ -41,14 +41,18 @@ public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding {
public init(decoder: PostboxDecoder) {
self.selected = decoder.decodeInt32ForKey("s", orElse: 0) != 0
self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data()
self.count = decoder.decodeInt32ForKey("c", orElse: 0)
self.count = decoder.decodeOptionalInt32ForKey("c")
self.isCorrect = decoder.decodeInt32ForKey("cr", orElse: 0) != 0
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.selected ? 1 : 0, forKey: "s")
encoder.encodeData(self.opaqueIdentifier, forKey: "i")
encoder.encodeInt32(self.count, forKey: "c")
if let count = self.count {
encoder.encodeInt32(count, forKey: "c")
} else {
encoder.encodeNil(forKey: "c")
}
encoder.encodeInt32(self.isCorrect ? 1 : 0, forKey: "cr")
}
}

View file

@ -147,7 +147,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
pollMediaFlags |= 1 << 1
}
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, solution: mappedSolution, solutionEntities: mappedSolutionEntities)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil))
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
return .single(nil)
@ -407,7 +407,7 @@ private final class PollResultsContextImpl {
if let voters = poll.results.voters {
for voter in voters {
if voter.opaqueIdentifier == option.opaqueIdentifier {
count = Int(voter.count)
count = Int(voter.count ?? 0)
}
}
}

View file

@ -1619,8 +1619,8 @@ func _internal_deleteBotPreviews(account: Account, peerId: PeerId, language: Str
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}
@ -1677,8 +1677,8 @@ func _internal_deleteBotPreviewsLanguage(account: Account, peerId: PeerId, langu
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}

View file

@ -3387,8 +3387,8 @@ public final class BotPreviewStoryListContext: StoryListContext {
var inputMedia: [Api.InputMedia] = []
for item in media {
if let image = item as? TelegramMediaImage, let resource = image.representations.last?.resource as? CloudPhotoSizeMediaResource {
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil)))
inputMedia.append(.inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
inputMedia.append(Api.InputMedia.inputMediaPhoto(.init(flags: 0, id: Api.InputPhoto.inputPhoto(.init(id: resource.photoId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference))), ttlSeconds: nil, video: nil)))
} else if let file = item as? TelegramMediaFile, let resource = file.resource as? CloudDocumentMediaResource {
inputMedia.append(.inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil)))
}

View file

@ -27,7 +27,7 @@ func _internal_summarizeMessage(account: Account, messageId: EngineMessage.Id, t
flags |= (1 << 0)
}
return account.network.request(Api.functions.messages.summarizeText(flags: flags, peer: inputPeer, id: messageId.id, toLang: translateToLang))
return account.network.request(Api.functions.messages.summarizeText(flags: flags, peer: inputPeer, id: messageId.id, toLang: translateToLang, tone: nil))
|> map(Optional.init)
|> mapError { error -> SummarizeError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {

View file

@ -3918,6 +3918,7 @@ private final class ResaleGiftsContextImpl {
private var sorting: ResaleGiftsContext.Sorting = .value
private var filterAttributes: [ResaleGiftsContext.Attribute] = []
private var starsOnly = false
private var gifts: [StarGift] = []
private var attributes: [StarGift.UniqueGift.Attribute] = []
@ -3963,6 +3964,7 @@ private final class ResaleGiftsContextImpl {
let network = self.account.network
let postbox = self.account.postbox
let sorting = self.sorting
let starsOnly = self.starsOnly
let filterAttributes = self.filterAttributes
let currentAttributesHash = self.attributesHash
@ -3987,6 +3989,10 @@ private final class ResaleGiftsContextImpl {
case .number:
flags |= (1 << 2)
}
if starsOnly {
flags |= (1 << 5)
}
var apiAttributes: [Api.StarGiftAttributeId]?
if !filterAttributes.isEmpty {
@ -4118,6 +4124,17 @@ private final class ResaleGiftsContextImpl {
self.loadMore()
}
func updateStarsOnly(_ starsOnly: Bool) {
guard self.starsOnly != starsOnly else {
return
}
self.starsOnly = starsOnly
self.dataState = .ready(canLoadMore: true, nextOffset: nil)
self.pushState()
self.loadMore()
}
func buyStarGift(slug: String, peerId: EnginePeer.Id, price: CurrencyAmount?) -> Signal<Never, BuyStarGiftError> {
var listingPrice: CurrencyAmount?
if let gift = self.gifts.first(where: { gift in
@ -4192,6 +4209,7 @@ private final class ResaleGiftsContextImpl {
let state = ResaleGiftsContext.State(
sorting: self.sorting,
filterAttributes: self.filterAttributes,
starsOnly: self.starsOnly,
gifts: self.gifts,
attributes: self.attributes,
attributeCount: self.attributeCount,
@ -4224,6 +4242,7 @@ public final class ResaleGiftsContext {
public var sorting: Sorting
public var filterAttributes: [Attribute]
public var starsOnly: Bool
public var gifts: [StarGift]
public var attributes: [StarGift.UniqueGift.Attribute]
public var attributeCount: [Attribute: Int32]
@ -4281,6 +4300,12 @@ public final class ResaleGiftsContext {
}
}
public func updateStarsOnly(_ starsOnly: Bool) {
self.impl.with { impl in
impl.updateStarsOnly(starsOnly)
}
}
public func buyStarGift(slug: String, peerId: EnginePeer.Id, price: CurrencyAmount? = nil) -> Signal<Never, BuyStarGiftError> {
return Signal { subscriber in
let disposable = MetaDisposable()

View file

@ -449,6 +449,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
public let dateAndStatusNode: ChatMessageDateAndStatusNode
private var badgeNode: ChatMessageInteractiveMediaBadge?
private var livePhotoIconNode: ASImageNode?
private var timestampContainerView: UIView?
private var timestampMaskView: UIImageView?
private var videoTimestampBackgroundLayer: SimpleLayer?
@ -1330,6 +1332,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}
}
var effectiveFile: TelegramMediaFile? = media as? TelegramMediaFile
if let story = media as? TelegramMediaStory {
isStory = true
@ -1507,6 +1510,8 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
messageMediaImageCancelInteractiveFetch(context: context, messageId: message.id, image: image, resource: resource)
}
})
effectiveFile = image.video
} else if let image = media as? TelegramMediaWebFile {
if hasCurrentVideoNode {
replaceVideoNode = true
@ -1525,7 +1530,57 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}, cancel: {
chatMessageWebFileCancelInteractiveFetch(account: context.account, image: image)
})
} else if var file = media as? TelegramMediaFile {
} else if let wallpaper = media as? WallpaperPreviewMedia {
updateImageSignal = { synchronousLoad, _ in
switch wallpaper.content {
case let .file(file, _, _, _, isTheme, _):
if isTheme {
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .file(FileMediaReference.message(message: MessageReference(message), media: file)), synchronousLoad: synchronousLoad)
} else {
var representations: [ImageRepresentationWithReference] = file.previewRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference($0.resource)) })
if file.mimeType == "image/svg+xml" || file.mimeType == "application/x-tgwallpattern" {
representations.append(ImageRepresentationWithReference(representation: .init(dimensions: PixelDimensions(width: 1440, height: 2960), resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource)))
}
if ["image/png", "image/svg+xml", "application/x-tgwallpattern"].contains(file.mimeType) {
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
if let value = value {
return .single(value.generator)
} else {
return .complete()
}
}
} else {
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file), representations: representations, alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true, synchronousLoad: synchronousLoad)
}
}
case let .image(representations):
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: nil, representations: representations.map({ ImageRepresentationWithReference(representation: $0, reference: .standalone(resource: $0.resource)) }), alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
case let .themeSettings(settings):
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .settings(settings))
case let .color(color):
return solidColorImage(color)
case let .gradient(colors, rotation):
return gradientImage(colors.map(UIColor.init(rgb:)), rotation: rotation ?? 0)
case .emoticon:
return solidColorImage(.black)
}
}
if case let .file(file, _, _, _, _, _) = wallpaper.content {
updatedFetchControls = FetchControls(fetch: { manual in
if let strongSelf = self {
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: manual).startStrict())
}
}, cancel: {
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
})
} else if case .themeSettings = wallpaper.content {
} else {
boundingSize = CGSize(width: boundingSize.width, height: boundingSize.width)
}
}
if var file = effectiveFile {
var uploading = false
if file.resource is VideoLibraryMediaResource {
uploading = true
@ -1590,7 +1645,9 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
return chatSecretMessageVideo(account: context.account, userLocation: .peer(message.id.peerId), videoReference: .message(message: MessageReference(message), media: file))
}
} else {
if let file = media as? TelegramMediaFile, let image = file.videoCover {
if let _ = media as? TelegramMediaImage {
} else if let image = file.videoCover {
updateImageSignal = { synchronousLoad, highQuality in
return chatMessagePhoto(postbox: context.account.postbox, userLocation: .peer(message.id.peerId), photoReference: .message(message: MessageReference(message), media: image), synchronousLoad: synchronousLoad, highQuality: highQuality)
}
@ -1644,55 +1701,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
}
})
} else if let wallpaper = media as? WallpaperPreviewMedia {
updateImageSignal = { synchronousLoad, _ in
switch wallpaper.content {
case let .file(file, _, _, _, isTheme, _):
if isTheme {
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .file(FileMediaReference.message(message: MessageReference(message), media: file)), synchronousLoad: synchronousLoad)
} else {
var representations: [ImageRepresentationWithReference] = file.previewRepresentations.map({ ImageRepresentationWithReference(representation: $0, reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference($0.resource)) })
if file.mimeType == "image/svg+xml" || file.mimeType == "application/x-tgwallpattern" {
representations.append(ImageRepresentationWithReference(representation: .init(dimensions: PixelDimensions(width: 1440, height: 2960), resource: file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), reference: AnyMediaReference.message(message: MessageReference(message), media: file).resourceReference(file.resource)))
}
if ["image/png", "image/svg+xml", "application/x-tgwallpattern"].contains(file.mimeType) {
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
if let value = value {
return .single(value.generator)
} else {
return .complete()
}
}
} else {
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: FileMediaReference.message(message: MessageReference(message), media: file), representations: representations, alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true, synchronousLoad: synchronousLoad)
}
}
case let .image(representations):
return wallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, fileReference: nil, representations: representations.map({ ImageRepresentationWithReference(representation: $0, reference: .standalone(resource: $0.resource)) }), alwaysShowThumbnailFirst: false, thumbnail: true, autoFetchFullSize: true)
case let .themeSettings(settings):
return themeImage(account: context.account, accountManager: context.sharedContext.accountManager, source: .settings(settings))
case let .color(color):
return solidColorImage(color)
case let .gradient(colors, rotation):
return gradientImage(colors.map(UIColor.init(rgb:)), rotation: rotation ?? 0)
case .emoticon:
return solidColorImage(.black)
}
}
if case let .file(file, _, _, _, _, _) = wallpaper.content {
updatedFetchControls = FetchControls(fetch: { manual in
if let strongSelf = self {
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: manual).startStrict())
}
}, cancel: {
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
})
} else if case .themeSettings = wallpaper.content {
} else {
boundingSize = CGSize(width: boundingSize.width, height: boundingSize.width)
}
}
}
if !reloadMedia {
@ -2024,11 +2032,29 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}
videoNode.isHidden = !owns
if owns {
videoNode.alpha = 1.0
videoNode.setBaseRate(1.0)
videoNode.continuePlayingWithoutSound()
if let image = strongSelf.media as? TelegramMediaImage, let _ = image.video {
videoNode.continuePlayingWithoutSound(actionAtEnd: .stop)
} else {
videoNode.continuePlayingWithoutSound()
}
}
}
}
videoNode.playbackCompleted = { [weak self] in
guard let self else {
return
}
if let image = self.media as? TelegramMediaImage, let _ = image.video {
self.videoNode?.alpha = 0.0
self.videoNode?.layer.allowsGroupOpacity = true
self.videoNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, completion: { _ in
self.videoNode?.allowsGroupOpacity = true
})
}
}
strongSelf.videoContent = videoContent
strongSelf.videoNode = videoNode
@ -2320,6 +2346,25 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}))
}
if let image = strongSelf.media as? TelegramMediaImage, let _ = image.video {
let livePhotoIconNode: ASImageNode
if let current = strongSelf.livePhotoIconNode {
livePhotoIconNode = current
} else {
livePhotoIconNode = ASImageNode()
livePhotoIconNode.image = UIImage(bundleImageName: "Chat/Message/LivePhoto")
strongSelf.pinchContainerNode.contentNode.addSubnode(livePhotoIconNode)
strongSelf.livePhotoIconNode = livePhotoIconNode
}
if let icon = livePhotoIconNode.image {
livePhotoIconNode.frame = CGRect(origin: CGPoint(x: 8.0, y: 8.0), size: icon.size)
}
} else if let livePhotoIconNode = strongSelf.livePhotoIconNode {
strongSelf.livePhotoIconNode = nil
livePhotoIconNode.removeFromSupernode()
}
if let updatedFetchControls = updatedFetchControls {
let _ = strongSelf.fetchControls.swap(updatedFetchControls)
@ -2890,7 +2935,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}
}
if let file = media as? TelegramMediaFile, file.isLivePhoto {
if let image = media as? TelegramMediaImage, let _ = image.video {
badgeContent = nil
if case .progress = state {
} else {

View file

@ -388,7 +388,8 @@ public final class ChatMessageAccessibilityData {
inner: for optionVoters in voters {
if optionVoters.opaqueIdentifier == poll.options[i].opaqueIdentifier {
optionVoterCount[i] = optionVoters.count
maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count)
//TODO:correct
maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count ?? 0)
break inner
}
}

View file

@ -125,6 +125,10 @@ public class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
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
}
if let _ = telegramImage.video {
automaticPlayback = true
}
} else if let telegramStory = media as? TelegramMediaStory {
selectedMedia = telegramStory
if let storyMedia = item.message.associatedStories[telegramStory.storyId], case let .item(storyItem) = storyMedia.get(Stories.StoredItem.self), let media = storyItem.media {

View file

@ -21,6 +21,7 @@ import ShimmeringLinkNode
private final class ChatMessagePollOptionRadioNodeParameters: NSObject {
let timestamp: Double
let isRectangle: Bool
let staticColor: UIColor
let animatedColor: UIColor
let fillColor: UIColor
@ -29,8 +30,9 @@ private final class ChatMessagePollOptionRadioNodeParameters: NSObject {
let isChecked: Bool?
let checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?
init(timestamp: Double, staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, offset: Double?, isChecked: Bool?, checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?) {
init(timestamp: Double, isRectangle: Bool, staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, offset: Double?, isChecked: Bool?, checkTransition: ChatMessagePollOptionRadioNodeCheckTransition?) {
self.timestamp = timestamp
self.isRectangle = isRectangle
self.staticColor = staticColor
self.animatedColor = animatedColor
self.fillColor = fillColor
@ -58,6 +60,7 @@ private final class ChatMessagePollOptionRadioNodeCheckTransition {
}
private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
private(set) var isRectangle = false
private(set) var staticColor: UIColor?
private(set) var animatedColor: UIColor?
private(set) var fillColor: UIColor?
@ -116,9 +119,13 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
}
}
func update(staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, isSelectable: Bool, isAnimating: Bool) {
func update(isRectangle: Bool, staticColor: UIColor, animatedColor: UIColor, fillColor: UIColor, foregroundColor: UIColor, isSelectable: Bool, isAnimating: Bool) {
var updated = false
let shouldHaveBeenAnimating = self.shouldBeAnimating
if self.isRectangle != isRectangle {
self.isRectangle = isRectangle
updated = true
}
if !staticColor.isEqual(self.staticColor) {
self.staticColor = staticColor
updated = true
@ -191,7 +198,7 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
if let startTime = self.startTime {
offset = CACurrentMediaTime() - startTime
}
return ChatMessagePollOptionRadioNodeParameters(timestamp: timestamp, staticColor: staticColor, animatedColor: animatedColor, fillColor: fillColor, foregroundColor: foregroundColor, offset: offset, isChecked: self.isChecked, checkTransition: self.checkTransition)
return ChatMessagePollOptionRadioNodeParameters(timestamp: timestamp, isRectangle: self.isRectangle, staticColor: staticColor, animatedColor: animatedColor, fillColor: fillColor, foregroundColor: foregroundColor, offset: offset, isChecked: self.isChecked, checkTransition: self.checkTransition)
} else {
return nil
}
@ -295,12 +302,23 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
if abs(diameter - 1.0) > CGFloat.ulpOfOne {
context.setStrokeColor(parameters.staticColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: bounds.width - 1.0, height: bounds.height - 1.0)))
if parameters.isRectangle{
context.addPath(UIBezierPath(roundedRect: CGRect(origin: .zero, size: bounds.size).insetBy(dx: 0.5, dy: 0.5), cornerRadius: 6.0).cgPath)
context.strokePath()
} else {
context.strokeEllipse(in: CGRect(origin: .zero, size: bounds.size).insetBy(dx: 0.5, dy: 0.5))
}
}
if !diameter.isZero {
context.setFillColor(parameters.fillColor.withAlphaComponent(alpha).cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(x: (bounds.width - diameter) / 2.0, y: (bounds.width - diameter) / 2.0), size: CGSize(width: diameter, height: diameter)))
if parameters.isRectangle{
context.addPath(UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: (bounds.width - diameter) / 2.0, y: (bounds.width - diameter) / 2.0), size: CGSize(width: diameter, height: diameter)), cornerRadius: 6.0).cgPath)
context.fillPath()
} else {
context.fillEllipse(in: CGRect(origin: CGPoint(x: (bounds.width - diameter) / 2.0, y: (bounds.width - diameter) / 2.0), size: CGSize(width: diameter, height: diameter)))
}
context.setLineWidth(1.5)
context.setLineJoin(.round)
@ -336,7 +354,13 @@ private final class ChatMessagePollOptionRadioNode: ASDisplayNode {
}
} else {
context.setStrokeColor(parameters.staticColor.cgColor)
context.strokeEllipse(in: CGRect(origin: CGPoint(x: 0.5, y: 0.5), size: CGSize(width: bounds.width - 1.0, height: bounds.height - 1.0)))
if parameters.isRectangle {
context.addPath(UIBezierPath(roundedRect: CGRect(origin: .zero, size: bounds.size).insetBy(dx: 0.5, dy: 0.5), cornerRadius: 6.0).cgPath)
context.strokePath()
} else {
context.strokeEllipse(in: CGRect(origin: .zero, size: bounds.size).insetBy(dx: 0.5, dy: 0.5))
}
}
}
}
@ -694,7 +718,7 @@ private final class ChatMessagePollOptionNode: ASDisplayNode {
}
let radioSize: CGFloat = 22.0
radioNode.frame = CGRect(origin: CGPoint(x: 12.0, y: 12.0), size: CGSize(width: radioSize, height: radioSize))
radioNode.update(staticColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioButton : presentationData.theme.theme.chat.message.outgoing.polls.radioButton, animatedColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioProgress : presentationData.theme.theme.chat.message.outgoing.polls.radioProgress, fillColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.bar : presentationData.theme.theme.chat.message.outgoing.polls.bar, foregroundColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.barIconForeground : presentationData.theme.theme.chat.message.outgoing.polls.barIconForeground, isSelectable: isSelectable, isAnimating: inProgress)
radioNode.update(isRectangle: poll.kind == .poll(multipleAnswers: true), staticColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioButton : presentationData.theme.theme.chat.message.outgoing.polls.radioButton, animatedColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.radioProgress : presentationData.theme.theme.chat.message.outgoing.polls.radioProgress, fillColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.bar : presentationData.theme.theme.chat.message.outgoing.polls.bar, foregroundColor: incoming ? presentationData.theme.theme.chat.message.incoming.polls.barIconForeground : presentationData.theme.theme.chat.message.outgoing.polls.barIconForeground, isSelectable: isSelectable, isAnimating: inProgress)
} else if let radioNode = node.radioNode {
node.radioNode = nil
if animated {
@ -1301,7 +1325,8 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
inner: for optionVoters in voters {
if optionVoters.opaqueIdentifier == poll.options[i].opaqueIdentifier {
optionVoterCount[i] = optionVoters.count
maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count)
//TODO:correct
maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count ?? 0)
break inner
}
}

View file

@ -5,6 +5,11 @@ import ComponentFlow
import CheckNode
public final class CheckComponent: Component {
public enum Mode {
case option
case checkbox
}
public struct Theme: Equatable {
public let backgroundColor: UIColor
public let strokeColor: UIColor
@ -40,21 +45,27 @@ public final class CheckComponent: Component {
}
}
let mode: Mode
let theme: Theme
let size: CGSize
let selected: Bool
public init(
mode: Mode = .option,
theme: Theme,
size: CGSize = CGSize(width: 22.0, height: 22.0),
selected: Bool
) {
self.mode = mode
self.theme = theme
self.size = size
self.selected = selected
}
public static func ==(lhs: CheckComponent, rhs: CheckComponent) -> Bool {
if lhs.mode != rhs.mode {
return false
}
if lhs.theme != rhs.theme {
return false
}

View file

@ -50,6 +50,7 @@ swift_library(
"//submodules/TelegramUI/Components/EdgeEffect",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/ContextControllerImpl",
"//submodules/TelegramUI/Components/CheckComponent",
],
visibility = [
"//visibility:public",

View file

@ -498,6 +498,15 @@ public final class GiftStoreContentComponent: Component {
}
}
func updateStarsOnly(_ starsOnly: Bool) {
guard let component = self.component else {
return
}
self.showLoading = true
component.resaleGiftsContext.updateStarsOnly(starsOnly)
component.scrollToTop()
}
func openSortContextMenu(sourceView: UIView) {
guard let component = self.component, let controller = component.controller(), !self.effectiveIsLoading else {
return
@ -540,6 +549,20 @@ public final class GiftStoreContentComponent: Component {
component.scrollToTop()
})))
items.append(.separator)
items.append(.action(ContextMenuActionItem(text: "All Listings", icon: { theme in
return component.resaleGiftsContext.currentState?.starsOnly == false ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
}, action: { [weak self] _, f in
f(.default)
self?.updateStarsOnly(false)
})))
items.append(.action(ContextMenuActionItem(text: "For Stars Only", icon: { theme in
return component.resaleGiftsContext.currentState?.starsOnly == true ? generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) : UIImage()
}, action: { [weak self] _, f in
f(.default)
self?.updateStarsOnly(true)
})))
let contextController = makeContextController(presentationData: presentationData, source: .reference(GiftStoreReferenceContentSource(controller: controller, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
contextController.dismissed = { [weak self] in
guard let self else {
@ -1174,6 +1197,7 @@ final class GiftStoreScreenComponent: Component {
private let title = ComponentView<Empty>()
private let subtitle = ComponentView<Empty>()
private let content = ComponentView<Empty>()
private let starsFilter = ComponentView<Empty>()
private var starsStateDisposable: Disposable?
private var starsState: StarsContext.State?
@ -1222,6 +1246,8 @@ final class GiftStoreScreenComponent: Component {
self.scrollView.setContentOffset(CGPoint(), animated: true)
}
var starsFilterIsHidden = false
var nextScrollTransition: ComponentTransition?
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.updateScrolling(bounds: scrollView.bounds, interactive: true, transition: self.nextScrollTransition ?? .immediate)
@ -1231,6 +1257,12 @@ final class GiftStoreScreenComponent: Component {
if let contentView = self.content.view as? GiftStoreContentComponent.View {
contentView.updateScrolling(bounds: bounds, interactive: interactive, transition: transition)
}
let starsFilterIsHidden = bounds.origin.y > 100.0
if starsFilterIsHidden != self.starsFilterIsHidden {
self.starsFilterIsHidden = starsFilterIsHidden
self.state?.updated(transition: .spring(duration: 0.4))
}
}
func presentBalanceMenu() {
@ -1471,6 +1503,30 @@ final class GiftStoreScreenComponent: Component {
transition.setFrame(view: subtitleView, frame: subtitleFrame)
}
//TODO:localize
let starsFilterSize = self.starsFilter.update(
transition: transition,
component: AnyComponent(
StarsFilterComponent(theme: theme, text: "Show listings for stars only", isSelected: component.resaleGiftsContext.currentState?.starsOnly ?? false, selectionUpdated: { [weak self] starsOnly in
guard let self else {
return
}
if let contentView = self.content.view as? GiftStoreContentComponent.View {
contentView.updateStarsOnly(starsOnly)
}
})
),
environment: {},
containerSize: CGSize(width: availableSize.width - headerSideInset * 2.0, height: 100.0)
)
let starsFilterFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - starsFilterSize.width) / 2.0), y: self.starsFilterIsHidden ? availableSize.height + 64.0 : availableSize.height - starsFilterSize.height - environment.safeInsets.bottom - 16.0), size: starsFilterSize)
if let starsFilterView = self.starsFilter.view {
if starsFilterView.superview == nil {
self.addSubview(starsFilterView)
}
transition.setFrame(view: starsFilterView, frame: starsFilterFrame)
}
let previousBounds = self.scrollView.bounds

View file

@ -0,0 +1,143 @@
import Foundation
import UIKit
import Display
import ComponentFlow
import SwiftSignalKit
import PlainButtonComponent
import MultilineTextComponent
import BundleIconComponent
import TextFormat
import AccountContext
import TelegramPresentationData
import GlassBackgroundComponent
import CheckComponent
final class StarsFilterComponent: Component {
let theme: PresentationTheme
let text: String
let isSelected: Bool
let selectionUpdated: (Bool) -> Void
init(
theme: PresentationTheme,
text: String,
isSelected: Bool,
selectionUpdated: @escaping (Bool) -> Void
) {
self.theme = theme
self.text = text
self.isSelected = isSelected
self.selectionUpdated = selectionUpdated
}
static func ==(lhs: StarsFilterComponent, rhs: StarsFilterComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.text != rhs.text {
return false
}
if lhs.isSelected != rhs.isSelected {
return false
}
return true
}
final class View: UIView {
private let backgroundView = GlassBackgroundView()
private let button = HighlightTrackingButton()
private let check = ComponentView<Empty>()
private let text = ComponentView<Empty>()
private var component: StarsFilterComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(self.backgroundView)
self.backgroundView.contentView.addSubview(self.button)
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func buttonPressed() {
guard let component = self.component else {
return
}
component.selectionUpdated(!component.isSelected)
}
func update(component: StarsFilterComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
let inset: CGFloat = 16.0
let textSize = self.text.update(
transition: .immediate,
component: AnyComponent(
Text(text: component.text, font: Font.regular(17.0), color: component.theme.list.itemPrimaryTextColor)
),
environment: {},
containerSize: CGSize(width: availableSize.width - 44.0, height: 52.0)
)
let checkTheme = CheckComponent.Theme(
backgroundColor: component.theme.list.itemCheckColors.fillColor,
strokeColor: component.theme.list.itemCheckColors.foregroundColor,
borderColor: component.theme.list.itemCheckColors.strokeColor,
overlayBorder: false,
hasInset: false,
hasShadow: false
)
let checkSize = self.check.update(
transition: .immediate,
component: AnyComponent(
CheckComponent(theme: checkTheme, selected: component.isSelected)
),
environment: {},
containerSize: CGSize(width: 22.0, height: 22.0)
)
let size = CGSize(width: inset + checkSize.width + inset + textSize.width + inset + 6.0, height: 52.0)
let textFrame = CGRect(origin: CGPoint(x: inset + checkSize.width + inset, y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
if let textView = self.text.view {
if textView.superview == nil {
self.backgroundView.contentView.addSubview(textView)
textView.isUserInteractionEnabled = false
}
transition.setFrame(view: textView, frame: textFrame)
}
let checkFrame = CGRect(origin: CGPoint(x: inset, y: floorToScreenPixels((size.height - checkSize.height) / 2.0)), size: checkSize)
if let checkView = self.check.view {
if checkView.superview == nil {
self.backgroundView.contentView.addSubview(checkView)
checkView.isUserInteractionEnabled = false
}
transition.setFrame(view: checkView, frame: checkFrame)
}
self.button.frame = CGRect(origin: .zero, size: size)
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: size))
self.backgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: component.theme.overallDarkAppearance, tintColor: .init(kind: .panel), isInteractive: true, transition: transition)
return size
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}