diff --git a/submodules/Postbox/Sources/ItemCollectionsView.swift b/submodules/Postbox/Sources/ItemCollectionsView.swift index 1c6c6bfee3..ffae1c60f2 100644 --- a/submodules/Postbox/Sources/ItemCollectionsView.swift +++ b/submodules/Postbox/Sources/ItemCollectionsView.swift @@ -42,9 +42,19 @@ public struct ItemCollectionViewEntry { } } -private func fetchLowerEntries(namespaces: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, collectionIndex: Int32, itemIndex: ItemCollectionItemIndex, count: Int, lowerCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, lowerItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> [ItemCollectionViewEntry] { +public struct RawItemCollectionViewEntry { + public let index: ItemCollectionViewEntryIndex + public let data: Data - var entries: [ItemCollectionViewEntry] = [] + public init(index: ItemCollectionViewEntryIndex, data: Data) { + self.index = index + self.data = data + } +} + +private func fetchLowerEntries(namespaces: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, collectionIndex: Int32, itemIndex: ItemCollectionItemIndex, count: Int, lowerCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, lowerItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> [RawItemCollectionViewEntry] { + + var entries: [RawItemCollectionViewEntry] = [] var currentCollectionIndex = collectionIndex var currentCollectionId = collectionId @@ -75,9 +85,9 @@ private func fetchLowerEntries(namespaces: [ItemCollectionId.Namespace], collect return entries } -private func fetchHigherEntries(namespaces: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, collectionIndex: Int32, itemIndex: ItemCollectionItemIndex, count: Int, higherCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, higherItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> [ItemCollectionViewEntry] { +private func fetchHigherEntries(namespaces: [ItemCollectionId.Namespace], collectionId: ItemCollectionId, collectionIndex: Int32, itemIndex: ItemCollectionItemIndex, count: Int, higherCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, higherItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> [RawItemCollectionViewEntry] { - var entries: [ItemCollectionViewEntry] = [] + var entries: [RawItemCollectionViewEntry] = [] var currentCollectionIndex = collectionIndex var currentCollectionId = collectionId @@ -115,11 +125,11 @@ private func aroundEntries(namespaces: [ItemCollectionId.Namespace], lowerCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, fetchLowerItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem], higherCollectionId: (_ namespaceList: [ItemCollectionId.Namespace], _ collectionId: ItemCollectionId, _ collectionIndex: Int32) -> (ItemCollectionId, Int32)?, - fetchHigherItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> ([ItemCollectionViewEntry], ItemCollectionViewEntry?, ItemCollectionViewEntry?) { - var lowerEntries: [ItemCollectionViewEntry] = [] - var upperEntries: [ItemCollectionViewEntry] = [] - var lower: ItemCollectionViewEntry? - var upper: ItemCollectionViewEntry? + fetchHigherItems: (_ collectionId: ItemCollectionId, _ itemIndex: ItemCollectionItemIndex, _ count: Int) -> [ItemCollectionItem]) -> ([RawItemCollectionViewEntry], RawItemCollectionViewEntry?, RawItemCollectionViewEntry?) { + var lowerEntries: [RawItemCollectionViewEntry] = [] + var upperEntries: [RawItemCollectionViewEntry] = [] + var lower: RawItemCollectionViewEntry? + var upper: RawItemCollectionViewEntry? let selectedAroundIndex: ItemCollectionViewEntryIndex if let aroundIndex = aroundIndex, let aroundCollectionIndex = collectionIndexById(aroundIndex.collectionId) { @@ -153,7 +163,7 @@ private func aroundEntries(namespaces: [ItemCollectionId.Namespace], } if lowerEntries.count != 0 && lowerEntries.count + upperEntries.count < count { - var additionalLowerEntries: [ItemCollectionViewEntry] = fetchLowerEntries(namespaces: namespaces, collectionId: lowerEntries.last!.index.collectionId, collectionIndex: lowerEntries.last!.index.collectionIndex, itemIndex: lowerEntries.last!.index.itemIndex, count: count - lowerEntries.count - upperEntries.count + 1, lowerCollectionId: lowerCollectionId, lowerItems: fetchLowerItems) + var additionalLowerEntries: [RawItemCollectionViewEntry] = fetchLowerEntries(namespaces: namespaces, collectionId: lowerEntries.last!.index.collectionId, collectionIndex: lowerEntries.last!.index.collectionIndex, itemIndex: lowerEntries.last!.index.itemIndex, count: count - lowerEntries.count - upperEntries.count + 1, lowerCollectionId: lowerCollectionId, lowerItems: fetchLowerItems) if additionalLowerEntries.count >= count - lowerEntries.count + upperEntries.count + 1 { lower = additionalLowerEntries.last @@ -162,7 +172,7 @@ private func aroundEntries(namespaces: [ItemCollectionId.Namespace], lowerEntries.append(contentsOf: additionalLowerEntries) } - var entries: [ItemCollectionViewEntry] = [] + var entries: [RawItemCollectionViewEntry] = [] entries.append(contentsOf: lowerEntries.reversed()) entries.append(contentsOf: upperEntries) return (entries: entries, lower: lower, upper: upper) diff --git a/submodules/TelegramCore/BUILD b/submodules/TelegramCore/BUILD index 2b09a36713..fe9bc15dbf 100644 --- a/submodules/TelegramCore/BUILD +++ b/submodules/TelegramCore/BUILD @@ -23,6 +23,7 @@ swift_library( "//submodules/Utils/RangeSet:RangeSet", "//submodules/Utils/DarwinDirStat", "//submodules/Emoji", + "//submodules/TelegramCore/FlatBuffers", "//submodules/TelegramCore/FlatSerialization", ], visibility = [ diff --git a/submodules/TelegramCore/FlatSerialization/BUILD b/submodules/TelegramCore/FlatSerialization/BUILD index e18b8eb401..8a4031fdc5 100644 --- a/submodules/TelegramCore/FlatSerialization/BUILD +++ b/submodules/TelegramCore/FlatSerialization/BUILD @@ -26,7 +26,7 @@ genrule( rm -rf "$$BUILD_DIR" mkdir -p "$$BUILD_DIR" - "$$FLATC" --swift -o "$$BUILD_DIR" {flatc_input} + "$$FLATC" --require-explicit-ids --swift -o "$$BUILD_DIR" {flatc_input} """.format( flatc_input=flatc_input ) + "\n" + "\n".join([ diff --git a/submodules/TelegramCore/FlatSerialization/Models/MessageId.fbs b/submodules/TelegramCore/FlatSerialization/Models/MessageId.fbs new file mode 100644 index 0000000000..94dd298248 --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/MessageId.fbs @@ -0,0 +1,9 @@ +include "PeerId.fbs"; + +namespace TelegramCore; + +struct MessageId { + peerId: PeerId (id: 0); + namespace: int32 (id: 1); + id: int32 (id: 2); +} diff --git a/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs b/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs new file mode 100644 index 0000000000..65fb77a3ba --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs @@ -0,0 +1,57 @@ +include "MessageId.fbs"; +include "PeerId.fbs"; +include "PeerReference.fbs"; +include "StickerPackReference.fbs"; + +namespace TelegramCore; + +table MessageReference { + peer:PeerReference (id: 0, required); + author:PeerReference (id: 1); + messageId:MessageId (id: 2, required); + timestamp:int32 (id: 3); + incoming:bool (id: 4); + secret:bool (id: 5); + threadId:int64 (id: 6); +} + +table WebpageReference { + webpageId:int64 (id: 0); + url:string (id: 1, required); +} + +table PartialMediaReference_Message { + message:MessageReference (id: 0); +} + +table PartialMediaReference_WebPage { + webPage:WebpageReference (id: 0); +} + +table PartialMediaReference_StickerPack { + stickerPack:StickerPackReference (id: 0, required); +} + +table PartialMediaReference_SavedGif { +} + +table PartialMediaReference_SavedSticker { +} + +table PartialMediaReference_RecentSticker { +} + +union PartialMediaReference_Value { + PartialMediaReference_Message, + PartialMediaReference_WebPage, + PartialMediaReference_StickerPack, + PartialMediaReference_SavedGif, + PartialMediaReference_SavedSticker, + PartialMediaReference_RecentSticker +} + +table PartialMediaReference { + value:PartialMediaReference_Value (id: 1, required); +} + +root_type PartialMediaReference; diff --git a/submodules/TelegramCore/FlatSerialization/Models/PeerId.fbs b/submodules/TelegramCore/FlatSerialization/Models/PeerId.fbs new file mode 100644 index 0000000000..935368f86e --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/PeerId.fbs @@ -0,0 +1,6 @@ +namespace TelegramCore; + +struct PeerId { + namespace: int32 (id: 0); + id: int64 (id: 1); +} diff --git a/submodules/TelegramCore/FlatSerialization/Models/PeerReference.fbs b/submodules/TelegramCore/FlatSerialization/Models/PeerReference.fbs new file mode 100644 index 0000000000..14bb67ad4c --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/PeerReference.fbs @@ -0,0 +1,27 @@ +namespace TelegramCore; + +table PeerReference_User { + id:int64 (id: 0); + accessHash:int64 (id: 1); +} + +table PeerReference_Group { + id:int64 (id: 0); +} + +table PeerReference_Channel { + id:int64 (id: 0); + accessHash:int64 (id: 1); +} + +union PeerReference_Value { + PeerReference_User, + PeerReference_Group, + PeerReference_Channel +} + +table PeerReference { + value:PeerReference_Value (id: 1, required); +} + +root_type PeerReference; diff --git a/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs b/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs new file mode 100644 index 0000000000..5b38b086c9 --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/StickerPackReference.fbs @@ -0,0 +1,54 @@ +namespace TelegramCore; + +table StickerPackReference_Id { + id:int64 (id: 0); + accessHash:int64 (id: 1); +} + +table StickerPackReference_Name { + name:string (id: 0, required); +} + +table StickerPackReference_AnimatedEmoji { +} + +table StickerPackReference_Dice { + emoji:string (id: 0, required); +} + +table StickerPackReference_AnimatedEmojiAnimations { +} + +table StickerPackReference_PremiumGifts { +} + +table StickerPackReference_EmojiGenericAnimations { +} + +table StickerPackReference_IconStatusEmoji { +} + +table StickerPackReference_IconTopicEmoji { +} + +table StickerPackReference_IconChannelStatusEmoji { +} + +union StickerPackReference_Value { + StickerPackReference_Id, + StickerPackReference_Name, + StickerPackReference_AnimatedEmoji, + StickerPackReference_Dice, + StickerPackReference_AnimatedEmojiAnimations, + StickerPackReference_PremiumGifts, + StickerPackReference_EmojiGenericAnimations, + StickerPackReference_IconStatusEmoji, + StickerPackReference_IconTopicEmoji, + StickerPackReference_IconChannelStatusEmoji +} + +table StickerPackReference { + value:StickerPackReference_Value (id: 1, required); +} + +root_type StickerPackReference; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFile.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFile.fbs index 0eefc28bfb..6cbe223dbc 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFile.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFile.fbs @@ -1,11 +1,25 @@ include "MediaId.fbs"; +include "TelegramMediaResource.fbs"; +include "TelegramMediaFileAttribute.fbs"; +include "TelegramMediaImageRepresentation.fbs"; include "VideoThumbnail.fbs"; +include "TelegramMediaImage.fbs"; +include "PartialMediaReference.fbs"; namespace TelegramCore; table TelegramMediaFile { - id: MediaId; - videoThumbnails: [VideoThumbnail]; + fileId:MediaId (id: 0, required); + partialReference:PartialMediaReference (id: 1); + resource:TelegramMediaResource (id: 2, required); + previewRepresentations:[TelegramMediaImageRepresentation] (id: 3); + videoThumbnails:[VideoThumbnail] (id: 4); + videoCover:TelegramMediaImage (id: 5); + immediateThumbnailData:[ubyte] (id: 6); + mimeType:string (id: 7, required); + size:int64 (id: 8); + attributes:[TelegramMediaFileAttribute] (id: 9); + alternativeRepresentations:[TelegramMediaFile] (id: 10); } root_type TelegramMediaFile; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFileAttribute.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFileAttribute.fbs new file mode 100644 index 0000000000..fb3614ce57 --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaFileAttribute.fbs @@ -0,0 +1,85 @@ +include "StickerPackReference.fbs"; + +namespace TelegramCore; + +table TelegramMediaFileAttribute_FileName { + fileName:string (id: 0, required); +} + +table StickerMaskCoords { + n:int32 (id: 0); + x:float32 (id: 1); + y:float32 (id: 2); + zoom:float32 (id: 3); +} + +table TelegramMediaFileAttribute_Sticker { + displayText:string (id: 0, required); + packReference:StickerPackReference (id: 1); + maskData:StickerMaskCoords (id: 2); +} + +table TelegramMediaFileAttribute_ImageSize { + width:int32 (id: 0); + height:int32 (id: 1); +} + +table TelegramMediaFileAttribute_Animated { +} + +table TelegramMediaFileAttribute_Video { + duration:float32 (id: 0); + width:int32 (id: 1); + height:int32 (id: 2); + flags:int32 (id: 3); + preloadSize:int32 (id: 4); + coverTime:float32 (id: 5); + videoCodec:string (id: 6); +} + +table TelegramMediaFileAttribute_Audio { + isVoice:bool (id: 0); + duration:int32 (id: 1); + title:string (id: 2); + performer:string (id: 3); + waveform:[ubyte] (id: 4); +} + +table TelegramMediaFileAttribute_HasLinkedStickers { +} + +table TelegramMediaFileAttribute_HintFileIsLarge { +} + +table TelegramMediaFileAttribute_HintIsValidated { +} + +table TelegramMediaFileAttribute_NoPremium { +} + +table TelegramMediaFileAttribute_CustomEmoji { + isPremium:bool (id: 0); + isSingleColor:bool (id: 1); + alt:string (id: 2, required); + packReference:StickerPackReference (id: 3); +} + +union TelegramMediaFileAttribute_Value { + TelegramMediaFileAttribute_FileName, + TelegramMediaFileAttribute_Sticker, + TelegramMediaFileAttribute_ImageSize, + TelegramMediaFileAttribute_Animated, + TelegramMediaFileAttribute_Video, + TelegramMediaFileAttribute_Audio, + TelegramMediaFileAttribute_HasLinkedStickers, + TelegramMediaFileAttribute_HintFileIsLarge, + TelegramMediaFileAttribute_HintIsValidated, + TelegramMediaFileAttribute_NoPremium, + TelegramMediaFileAttribute_CustomEmoji +} + +table TelegramMediaFileAttribute { + value:TelegramMediaFileAttribute_Value (id: 1, required); +} + +root_type TelegramMediaFileAttribute; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImage.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImage.fbs new file mode 100644 index 0000000000..107e3f6476 --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImage.fbs @@ -0,0 +1,51 @@ +include "MediaId.fbs"; +include "TelegramMediaImageRepresentation.fbs"; +include "StickerPackReference.fbs"; +include "PartialMediaReference.fbs"; + +namespace TelegramCore; + +table TelegramMediaImageReference { + imageId:int64 (id: 0); + accessHash:int64 (id: 1); + fileReference:[ubyte] (id: 2); +} + +table VideoRepresentation { + width:int32 (id: 0); + height:int32 (id: 1); + resource:TelegramMediaResource (id: 2, required); + startTimestamp:float32 (id: 3); +} + +table EmojiMarkup_Content_Emoji { + fileId:int64 (id: 0); +} + +table EmojiMarkup_Content_Sticker { + packReference:StickerPackReference (id: 0, required); + fileId:int64 (id: 1); +} + +union EmojiMarkup_Content { + EmojiMarkup_Content_Emoji, + EmojiMarkup_Content_Sticker +} + +table EmojiMarkup { + content:EmojiMarkup_Content (id: 1, required); + backgroundColors:[int32] (id: 2); +} + +table TelegramMediaImage { + imageId:MediaId (id: 0, required); + representations:[TelegramMediaImageRepresentation] (id: 1); + videoRepresentations:[VideoRepresentation] (id: 2); + immediateThumbnailData:[ubyte] (id: 3); + emojiMarkup:EmojiMarkup (id: 4); + reference:TelegramMediaImageReference (id: 5); + partialReference:PartialMediaReference (id: 6); + flags:int32 (id: 7); +} + +root_type TelegramMediaImage; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImageRepresentation.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImageRepresentation.fbs new file mode 100644 index 0000000000..58b5c922b3 --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaImageRepresentation.fbs @@ -0,0 +1,22 @@ +include "TelegramMediaResource.fbs"; + +namespace TelegramCore; + +enum TelegramMediaImageRepresentation_TypeHint:int32 { + generic = 0, + animated = 1, + video = 2 +} + +table TelegramMediaImageRepresentation { + width:int32 (id: 0); + height:int32 (id: 1); + resource:TelegramMediaResource (id: 2, required); + progressiveSizes:[int32] (id: 3); + immediateThumbnailData:[ubyte] (id: 4); + hasVideo:bool (id: 5); + isPersonal:bool (id: 6); + typeHint:TelegramMediaImageRepresentation_TypeHint (id: 7); +} + +root_type TelegramMediaImageRepresentation; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaResource.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaResource.fbs new file mode 100644 index 0000000000..e28f7b900a --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramMediaResource.fbs @@ -0,0 +1,78 @@ +namespace TelegramCore; + +table TelegramMediaResource_CloudFileMediaResource { + datacenterId:int32 (id: 0); + volumeId:int64 (id: 1); + localId:int32 (id: 2); + secret:int64 (id: 3); + size:int64 (id: 4); + fileReference:[ubyte] (id: 5); +} + +table TelegramMediaResource_CloudDocumentSizeMediaResource { + datacenterId:int32 (id: 0); + documentId:int64 (id: 1); + accessHash:int64 (id: 2); + sizeSpec:string (id: 3, required); + fileReference:[ubyte] (id: 4); +} + +table TelegramMediaResource_CloudPhotoSizeMediaResource { + datacenterId:int32 (id: 0); + photoId:int64 (id: 1); + accessHash:int64 (id: 2); + sizeSpec:string (id: 3, required); + size:int64 (id: 4); + fileReference:[ubyte] (id: 5); +} + +enum CloudPeerPhotoSizeSpec:int32 { + small = 0, + fullSize = 1 +} + +table TelegramMediaResource_CloudPeerPhotoSizeMediaResource { + datacenterId:int32 (id: 0); + photoId:int64 (id: 1); + sizeSpec:CloudPeerPhotoSizeSpec (id: 2); + volumeId:int64 (id: 3); + localId:int32 (id: 4); +} + +table TelegramMediaResource_CloudStickerPackThumbnailMediaResource { + datacenterId:int32 (id: 0); + thumbVersion:int32 (id: 1); + volumeId:int64 (id: 2); + localId:int32 (id: 3); +} + +table TelegramMediaResource_CloudDocumentMediaResource { + datacenterId:int32 (id: 0); + fileId:int64 (id: 1); + accessHash:int64 (id: 2); + size:int64 (id: 3); + fileReference:[ubyte] (id: 4); + fileName:string (id: 5); +} + +table TelegramMediaResource_LocalFileMediaResource { + fileId:int64 (id: 0); + size:int64 (id: 1); + isSecretRelated:bool (id: 2); +} + +union TelegramMediaResource_Value { + TelegramMediaResource_CloudFileMediaResource, + TelegramMediaResource_CloudDocumentSizeMediaResource, + TelegramMediaResource_CloudPhotoSizeMediaResource, + TelegramMediaResource_CloudPeerPhotoSizeMediaResource, + TelegramMediaResource_CloudStickerPackThumbnailMediaResource, + TelegramMediaResource_CloudDocumentMediaResource, + TelegramMediaResource_LocalFileMediaResource +} + +table TelegramMediaResource { + value:TelegramMediaResource_Value (id: 1, required); +} + +root_type TelegramMediaResource; diff --git a/submodules/TelegramCore/FlatSerialization/Models/VideoThumbnail.fbs b/submodules/TelegramCore/FlatSerialization/Models/VideoThumbnail.fbs index 62a84090f9..d39a56a2b9 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/VideoThumbnail.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/VideoThumbnail.fbs @@ -1,7 +1,11 @@ -include "PixelDimensions.fbs"; +include "TelegramMediaResource.fbs"; namespace TelegramCore; -struct VideoThumbnail { - dimensions: PixelDimensions; +table VideoThumbnail { + width:int32 (id: 0); + height:int32 (id: 1); + resource:TelegramMediaResource (id: 2, required); } + +root_type VideoThumbnail; diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift index 42ecf39aac..92beb9f3ff 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift @@ -2,7 +2,6 @@ import Foundation import Postbox import TelegramApi - func dimensionsForFileAttributes(_ attributes: [TelegramMediaFileAttribute]) -> PixelDimensions? { for attribute in attributes { switch attribute { @@ -183,7 +182,7 @@ func telegramMediaFileFromApiDocument(_ document: Api.Document, altDocuments: [A } } - var alternativeRepresentations: [Media] = [] + var alternativeRepresentations: [TelegramMediaFile] = [] if let altDocuments { alternativeRepresentations = altDocuments.compactMap { telegramMediaFileFromApiDocument($0, altDocuments: []) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift index 2c83744200..87a9eddab0 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CloudFileMediaResource.swift @@ -1,6 +1,8 @@ import Foundation import Postbox import TelegramApi +import FlatBuffers +import FlatSerialization public struct CloudFileMediaResourceId: Hashable, Equatable { let datacenterId: Int @@ -956,3 +958,215 @@ public final class WallpaperDataResource: TelegramMediaResource { return true } } + +public func TelegramMediaResource_parse(flatBuffersData data: Data) throws -> TelegramMediaResource { + var byteBuffer = ByteBuffer(data: data) + let flatBuffersObject: TelegramCore_TelegramMediaResource = try getCheckedRoot(byteBuffer: &byteBuffer) + + return try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject) +} + +public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_TelegramMediaResource) throws -> TelegramMediaResource { + switch flatBuffersObject.valueType { + case .telegrammediaresourceCloudfilemediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudFileMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return CloudFileMediaResource( + datacenterId: Int(value.datacenterId), + volumeId: value.volumeId, + localId: value.localId, + secret: value.secret, + size: value.size == 0 ? nil : value.size, + fileReference: value.fileReference.isEmpty ? nil : Data(value.fileReference) + ) + case .telegrammediaresourceClouddocumentsizemediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return CloudDocumentSizeMediaResource( + datacenterId: value.datacenterId, + documentId: value.documentId, + accessHash: value.accessHash, + sizeSpec: value.sizeSpec, + fileReference: value.fileReference.isEmpty ? nil : Data(value.fileReference) + ) + case .telegrammediaresourceCloudphotosizemediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return CloudPhotoSizeMediaResource( + datacenterId: value.datacenterId, + photoId: value.photoId, + accessHash: value.accessHash, + sizeSpec: value.sizeSpec, + size: value.size == 0 ? nil : value.size, + fileReference: value.fileReference.isEmpty ? nil : Data(value.fileReference) + ) + case .telegrammediaresourceCloudpeerphotosizemediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + let sizeSpec: CloudPeerPhotoSizeSpec + switch value.sizeSpec { + case .small: + sizeSpec = .small + case .fullSize: + sizeSpec = .fullSize + } + return CloudPeerPhotoSizeMediaResource( + datacenterId: value.datacenterId, + photoId: value.photoId == Int64.min ? nil : value.photoId, + sizeSpec: sizeSpec, + volumeId: value.volumeId == Int64.min ? nil : value.volumeId, + localId: value.localId == Int32.min ? nil : value.localId + ) + case .telegrammediaresourceCloudstickerpackthumbnailmediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return CloudStickerPackThumbnailMediaResource( + datacenterId: value.datacenterId, + thumbVersion: value.thumbVersion == Int32.min ? nil : value.thumbVersion, + volumeId: value.volumeId == Int64.min ? nil : value.volumeId, + localId: value.localId == Int32.min ? nil : value.localId + ) + case .telegrammediaresourceClouddocumentmediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return CloudDocumentMediaResource( + datacenterId: Int(value.datacenterId), + fileId: value.fileId, + accessHash: value.accessHash, + size: value.size == 0 ? nil : value.size, + fileReference: value.fileReference.isEmpty ? nil : Data(value.fileReference), + fileName: value.fileName + ) + case .telegrammediaresourceLocalfilemediaresource: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_LocalFileMediaResource.self) else { + throw FlatBuffersError.missingRequiredField + } + return LocalFileMediaResource( + fileId: value.fileId, + size: value.size == Int64.min ? nil : value.size, + isSecretRelated: value.isSecretRelated + ) + case .none_: + throw FlatBuffersError.missingRequiredField + } +} + +public func TelegramMediaResource_serialize(resource: TelegramMediaResource, flatBuffersBuilder builder: inout FlatBufferBuilder) -> Offset? { + switch resource { + case let resource as CloudFileMediaResource: + let fileReferenceOffset = resource.fileReference.flatMap { builder.createVector(bytes: $0) } + + let start = TelegramCore_TelegramMediaResource_CloudFileMediaResource.startTelegramMediaResource_CloudFileMediaResource(&builder) + + TelegramCore_TelegramMediaResource_CloudFileMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudFileMediaResource.add(volumeId: resource.volumeId, &builder) + TelegramCore_TelegramMediaResource_CloudFileMediaResource.add(localId: resource.localId, &builder) + TelegramCore_TelegramMediaResource_CloudFileMediaResource.add(secret: resource.secret, &builder) + TelegramCore_TelegramMediaResource_CloudFileMediaResource.add(size: resource.size ?? 0, &builder) + + if let fileReferenceOffset { + TelegramCore_TelegramMediaResource_CloudFileMediaResource.addVectorOf(fileReference: fileReferenceOffset, &builder) + } + + let offset = TelegramCore_TelegramMediaResource_CloudFileMediaResource.endTelegramMediaResource_CloudFileMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceCloudfilemediaresource, valueOffset: offset) + case let resource as CloudDocumentSizeMediaResource: + let sizeSpecOffset = builder.create(string: resource.sizeSpec) + let fileReferenceOffset = resource.fileReference.flatMap { builder.createVector(bytes: $0) } + + let start = TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.startTelegramMediaResource_CloudDocumentSizeMediaResource(&builder) + + TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.add(documentId: resource.documentId, &builder) + TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.add(accessHash: resource.accessHash, &builder) + TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.add(sizeSpec: sizeSpecOffset, &builder) + if let fileReferenceOffset { + TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.addVectorOf(fileReference: fileReferenceOffset, &builder) + } + + let offset = TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.endTelegramMediaResource_CloudDocumentSizeMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceClouddocumentsizemediaresource, valueOffset: offset) + case let resource as CloudPhotoSizeMediaResource: + let sizeSpecOffset = builder.create(string: resource.sizeSpec) + let start = TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.startTelegramMediaResource_CloudPhotoSizeMediaResource(&builder) + let fileReferenceOffset = resource.fileReference.flatMap { builder.createVector(bytes: $0) } + + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.add(photoId: resource.photoId, &builder) + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.add(accessHash: resource.accessHash, &builder) + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.add(sizeSpec: sizeSpecOffset, &builder) + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.add(size: resource.size ?? 0, &builder) + if let fileReferenceOffset { + TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.addVectorOf(fileReference: fileReferenceOffset, &builder) + } + + let offset = TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.endTelegramMediaResource_CloudPhotoSizeMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceCloudphotosizemediaresource, valueOffset: offset) + case let resource as CloudPeerPhotoSizeMediaResource: + let start = TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.startTelegramMediaResource_CloudPeerPhotoSizeMediaResource(&builder) + + let sizeSpec: TelegramCore_CloudPeerPhotoSizeSpec + switch resource.sizeSpec { + case .small: + sizeSpec = .small + case .fullSize: + sizeSpec = .fullSize + } + + TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.add(photoId: resource.photoId ?? Int64.min, &builder) + TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.add(sizeSpec: sizeSpec, &builder) + TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.add(volumeId: resource.volumeId ?? Int64.min, &builder) + TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.add(localId: resource.localId ?? Int32.min, &builder) + + let offset = TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.endTelegramMediaResource_CloudPeerPhotoSizeMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceCloudpeerphotosizemediaresource, valueOffset: offset) + case let resource as CloudStickerPackThumbnailMediaResource: + let start = TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.startTelegramMediaResource_CloudStickerPackThumbnailMediaResource(&builder) + + TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.add(thumbVersion: resource.thumbVersion ?? Int32.min, &builder) + TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.add(volumeId: resource.volumeId ?? Int64.min, &builder) + TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.add(localId: resource.localId ?? Int32.min, &builder) + + let offset = TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.endTelegramMediaResource_CloudStickerPackThumbnailMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceCloudstickerpackthumbnailmediaresource, valueOffset: offset) + case let resource as CloudDocumentMediaResource: + let fileNameOffset = resource.fileName.flatMap { builder.create(string: $0) } + let fileReferenceOffset = resource.fileReference.flatMap { builder.createVector(bytes: $0) } + + let start = TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.startTelegramMediaResource_CloudDocumentMediaResource(&builder) + + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.add(datacenterId: Int32(resource.datacenterId), &builder) + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.add(fileId: resource.fileId, &builder) + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.add(accessHash: resource.accessHash, &builder) + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.add(size: resource.size ?? 0, &builder) + if let fileReferenceOffset { + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.addVectorOf(fileReference: fileReferenceOffset, &builder) + } + if let fileNameOffset { + TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.add(fileName: fileNameOffset, &builder) + } + + let offset = TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.endTelegramMediaResource_CloudDocumentMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceClouddocumentmediaresource, valueOffset: offset) + case let resource as LocalFileMediaResource: + let start = TelegramCore_TelegramMediaResource_LocalFileMediaResource.startTelegramMediaResource_LocalFileMediaResource(&builder) + + TelegramCore_TelegramMediaResource_LocalFileMediaResource.add(fileId: resource.fileId, &builder) + TelegramCore_TelegramMediaResource_LocalFileMediaResource.add(size: resource.size ?? Int64.min, &builder) + TelegramCore_TelegramMediaResource_LocalFileMediaResource.add(isSecretRelated: resource.isSecretRelated, &builder) + + let offset = TelegramCore_TelegramMediaResource_LocalFileMediaResource.endTelegramMediaResource_LocalFileMediaResource(&builder, start: start) + return TelegramCore_TelegramMediaResource.createTelegramMediaResource(&builder, valueType: .telegrammediaresourceLocalfilemediaresource, valueOffset: offset) + default: + assertionFailure() + return nil + } +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift index fb8c128a80..d0f1e0a6bc 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift @@ -65,6 +65,10 @@ public struct MessageReference: PostboxCoding, Hashable, Equatable { } } + init(content: MessageReferenceContent) { + self.content = content + } + public init(_ message: Message) { if message.id.namespace != Namespaces.Message.Local, let peer = message.peers[message.id.peerId], let inputPeer = PeerReference(peer) { let author: PeerReference? @@ -145,6 +149,10 @@ public enum MessageReferenceContent: PostboxCoding, Hashable, Equatable { public struct WebpageReference: PostboxCoding, Hashable, Equatable { public let content: WebpageReferenceContent + init(content: WebpageReferenceContent) { + self.content = content + } + public init(_ webPage: TelegramMediaWebpage) { if case let .Loaded(content) = webPage.content { self.content = .webPage(id: webPage.webpageId.id, url: content.url) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift new file mode 100644 index 0000000000..bbdea3bf4d --- /dev/null +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift @@ -0,0 +1,146 @@ +import Postbox +import FlatBuffers +import FlatSerialization + +public extension PeerId { + init(flatBuffersObject: TelegramCore_PeerId) { + self.init(namespace: PeerId.Namespace._internalFromInt32Value(flatBuffersObject.namespace), id: PeerId.Id._internalFromInt64Value(flatBuffersObject.id)) + } +} + +public extension MessageId { + init(flatBuffersObject: TelegramCore_MessageId) { + self.init(peerId: PeerId(flatBuffersObject: flatBuffersObject.peerId), namespace: flatBuffersObject.namespace, id: flatBuffersObject.id) + } +} + +public extension MessageReference { + init(flatBuffersObject: TelegramCore_MessageReference) throws { + self.init(content: .message( + peer: try PeerReference(flatBuffersObject: flatBuffersObject.peer), + author: try flatBuffersObject.author.flatMap { try PeerReference(flatBuffersObject: $0) }, + id: MessageId(flatBuffersObject: flatBuffersObject.messageId), + timestamp: flatBuffersObject.timestamp, + incoming: flatBuffersObject.incoming, + secret: flatBuffersObject.secret, + threadId: flatBuffersObject.threadId == Int64.min ? nil : flatBuffersObject.threadId) + ) + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset? { + switch self.content { + case let .message(peer, author, id, timestamp, incoming, secret, threadId): + let peerOffset = peer.encodeToFlatBuffers(builder: &builder) + let authorOffset = author.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + + let start = TelegramCore_MessageReference.startMessageReference(&builder) + + TelegramCore_MessageReference.add(peer: peerOffset, &builder) + if let authorOffset { + TelegramCore_MessageReference.add(author: authorOffset, &builder) + } + TelegramCore_MessageReference.add(messageId: TelegramCore_MessageId(peerId: TelegramCore_PeerId(namespace: id.peerId.namespace._internalGetInt32Value(), id: id.peerId.id._internalGetInt64Value()), namespace: id.namespace, id: id.id), &builder) + TelegramCore_MessageReference.add(timestamp: timestamp, &builder) + TelegramCore_MessageReference.add(incoming: incoming, &builder) + TelegramCore_MessageReference.add(secret: secret, &builder) + TelegramCore_MessageReference.add(threadId: threadId ?? Int64.min, &builder) + + return TelegramCore_MessageReference.endMessageReference(&builder, start: start) + case .none: + return nil + } + } +} + +public extension WebpageReference { + init(flatBuffersObject: TelegramCore_WebpageReference) throws { + self.init(content: .webPage(id: flatBuffersObject.webpageId, url: flatBuffersObject.url)) + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset? { + switch self.content { + case let .webPage(id, url): + let urlOffset = builder.create(string: url) + + let start = TelegramCore_WebpageReference.startWebpageReference(&builder) + + TelegramCore_WebpageReference.add(webpageId: id, &builder) + TelegramCore_WebpageReference.add(url: urlOffset, &builder) + + return TelegramCore_WebpageReference.endWebpageReference(&builder, start: start) + case .none: + return nil + } + } +} + +public extension PartialMediaReference { + init(flatBuffersObject: TelegramCore_PartialMediaReference) throws { + switch flatBuffersObject.valueType { + case .partialmediareferenceMessage: + guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_Message.self) else { + throw FlatBuffersError.missingRequiredField + } + if let message = value.message { + self = .message(message: try MessageReference(flatBuffersObject: message)) + } else { + self = .message(message: MessageReference(content: .none)) + } + case .partialmediareferenceWebpage: + guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_WebPage.self) else { + throw FlatBuffersError.missingRequiredField + } + if let webPage = value.webPage { + self = .webPage(webPage: try WebpageReference(flatBuffersObject: webPage)) + } else { + self = .webPage(webPage: WebpageReference(content: .none)) + } + case .partialmediareferenceStickerpack: + guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_StickerPack.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .stickerPack(stickerPack: try StickerPackReference(flatBuffersObject: value.stickerPack)) + case .partialmediareferenceSavedgif: + self = .savedGif + case .partialmediareferenceSavedsticker: + self = .savedSticker + case .partialmediareferenceRecentsticker: + self = .recentSticker + case .none_: + throw FlatBuffersError.missingRequiredField + } + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + switch self { + case let .message(message): + let messageOffset = message.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_PartialMediaReference_Message.startPartialMediaReference_Message(&builder) + if let messageOffset { + TelegramCore_PartialMediaReference_Message.add(message: messageOffset, &builder) + } + return TelegramCore_PartialMediaReference_Message.endPartialMediaReference_Message(&builder, start: start) + case let .webPage(webPage): + let webpageOffset = webPage.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_PartialMediaReference_WebPage.startPartialMediaReference_WebPage(&builder) + if let webpageOffset { + TelegramCore_PartialMediaReference_WebPage.add(webPage: webpageOffset, &builder) + } + return TelegramCore_PartialMediaReference_WebPage.endPartialMediaReference_WebPage(&builder, start: start) + case let .stickerPack(stickerPack): + let stickerPackOffset = stickerPack.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_PartialMediaReference_StickerPack.startPartialMediaReference_StickerPack(&builder) + TelegramCore_PartialMediaReference_StickerPack.add(stickerPack: stickerPackOffset, &builder) + return TelegramCore_PartialMediaReference_StickerPack.endPartialMediaReference_StickerPack(&builder, start: start) + case .savedGif: + let start = TelegramCore_PartialMediaReference_SavedGif.startPartialMediaReference_SavedGif(&builder) + return TelegramCore_PartialMediaReference_SavedGif.endPartialMediaReference_SavedGif(&builder, start: start) + case .savedSticker: + let start = TelegramCore_PartialMediaReference_SavedSticker.startPartialMediaReference_SavedSticker(&builder) + return TelegramCore_PartialMediaReference_SavedSticker.endPartialMediaReference_SavedSticker(&builder, start: start) + case .recentSticker: + let start = TelegramCore_PartialMediaReference_RecentSticker.startPartialMediaReference_RecentSticker(&builder) + return TelegramCore_PartialMediaReference_RecentSticker.endPartialMediaReference_RecentSticker(&builder, start: start) + } + } +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_PeerReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_PeerReference.swift index 6830c2b3f7..270f0bcb17 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_PeerReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_PeerReference.swift @@ -1,4 +1,6 @@ import Postbox +import FlatBuffers +import FlatSerialization public enum PeerReference: PostboxCoding, Hashable, Equatable { case user(id: Int64, accessHash: Int64) @@ -73,4 +75,48 @@ public enum PeerReference: PostboxCoding, Hashable, Equatable { return nil } } + + public init(flatBuffersObject: TelegramCore_PeerReference) throws { + switch flatBuffersObject.valueType { + case .peerreferenceUser: + guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_User.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .user(id: value.id, accessHash: value.accessHash) + case .peerreferenceGroup: + guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_Group.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .group(id: value.id) + case .peerreferenceChannel: + guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_Channel.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .channel(id: value.id, accessHash: value.accessHash) + case .none_: + throw FlatBuffersError.missingRequiredField + } + } + + public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + switch self { + case let .user(id, accessHash): + let start = TelegramCore_PeerReference.startPeerReference(&builder) + TelegramCore_PeerReference_User.add(id: id, &builder) + TelegramCore_PeerReference_User.add(accessHash: accessHash, &builder) + let offset = TelegramCore_PeerReference_User.endPeerReference_User(&builder, start: start) + return TelegramCore_PeerReference.createPeerReference(&builder, valueType: .peerreferenceUser, valueOffset: offset) + case let .group(id): + let start = TelegramCore_PeerReference.startPeerReference(&builder) + TelegramCore_PeerReference_Group.add(id: id, &builder) + let offset = TelegramCore_PeerReference_Group.endPeerReference_Group(&builder, start: start) + return TelegramCore_PeerReference.createPeerReference(&builder, valueType: .peerreferenceUser, valueOffset: offset) + case let .channel(id, accessHash): + let start = TelegramCore_PeerReference.startPeerReference(&builder) + TelegramCore_PeerReference_Channel.add(id: id, &builder) + TelegramCore_PeerReference_Channel.add(accessHash: accessHash, &builder) + let offset = TelegramCore_PeerReference_Channel.endPeerReference_Channel(&builder, start: start) + return TelegramCore_PeerReference.createPeerReference(&builder, valueType: .peerreferenceUser, valueOffset: offset) + } + } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackItem.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackItem.swift index c5333a4946..3ce9e09bbc 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackItem.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StickerPackItem.swift @@ -1,19 +1,25 @@ +import Foundation import Postbox +import FlatBuffers +import FlatSerialization public final class StickerPackItem: ItemCollectionItem, Equatable { public let index: ItemCollectionItemIndex public let file: TelegramMediaFile + public let serializedFile: Data public let indexKeys: [MemoryBuffer] public init(index: ItemCollectionItemIndex, file: TelegramMediaFile, indexKeys: [MemoryBuffer]) { self.index = index self.file = file + self.serializedFile = file.encodeToFlatBuffersData() self.indexKeys = indexKeys } public init(decoder: PostboxDecoder) { self.index = ItemCollectionItemIndex(index: decoder.decodeInt32ForKey("i.n", orElse: 0), id: decoder.decodeInt64ForKey("i.i", orElse: 0)) self.file = decoder.decodeObjectForKey("f") as! TelegramMediaFile + self.serializedFile = decoder.decodeDataForKey("fd") ?? self.file.encodeToFlatBuffersData() self.indexKeys = decoder.decodeBytesArrayForKey("s") } @@ -21,6 +27,7 @@ public final class StickerPackItem: ItemCollectionItem, Equatable { encoder.encodeInt32(self.index.index, forKey: "i.n") encoder.encodeInt64(self.index.id, forKey: "i.i") encoder.encodeObject(self.file, forKey: "f") + encoder.encodeData(self.serializedFile, forKey: "fd") encoder.encodeBytesArray(self.indexKeys, forKey: "s") } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift index 553c30e32d..069c95b6f5 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaFile.swift @@ -1,5 +1,7 @@ import Foundation import Postbox +import FlatBuffers +import FlatSerialization private let typeFileName: Int32 = 0 private let typeSticker: Int32 = 1 @@ -13,6 +15,11 @@ private let typeHintIsValidated: Int32 = 8 private let typeNoPremium: Int32 = 9 private let typeCustomEmoji: Int32 = 10 +enum FlatBuffersError: Error { + case missingRequiredField + case invalidUnionType +} + public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { case id(id: Int64, accessHash: Int64) case name(String) @@ -120,6 +127,96 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable { } } + init(flatBuffersObject: TelegramCore_StickerPackReference) throws { + switch flatBuffersObject.valueType { + case .stickerpackreferenceId: + guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Id.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .id(id: value.id, accessHash: value.accessHash) + case .stickerpackreferenceName: + guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Name.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .name(value.name) + case .stickerpackreferenceAnimatedemoji: + self = .animatedEmoji + case .stickerpackreferenceDice: + guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Dice.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .dice(value.emoji) + case .stickerpackreferenceAnimatedemojianimations: + self = .animatedEmojiAnimations + case .stickerpackreferencePremiumgifts: + self = .premiumGifts + case .stickerpackreferenceEmojigenericanimations: + self = .emojiGenericAnimations + case .stickerpackreferenceIconstatusemoji: + self = .iconStatusEmoji + case .stickerpackreferenceIcontopicemoji: + self = .iconTopicEmoji + case .stickerpackreferenceIconchannelstatusemoji: + self = .iconChannelStatusEmoji + case .none_: + throw FlatBuffersError.missingRequiredField + } + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let valueType: TelegramCore_StickerPackReference_Value + let offset: Offset + switch self { + case let .id(id, accessHash): + valueType = .stickerpackreferenceId + let start = TelegramCore_StickerPackReference_Id.startStickerPackReference_Id(&builder) + TelegramCore_StickerPackReference_Id.add(id: id, &builder) + TelegramCore_StickerPackReference_Id.add(accessHash: accessHash, &builder) + offset = TelegramCore_StickerPackReference_Id.endStickerPackReference_Id(&builder, start: start) + case let .name(name): + valueType = .stickerpackreferenceName + let nameOffset = builder.create(string: name) + let start = TelegramCore_StickerPackReference_Name.startStickerPackReference_Name(&builder) + TelegramCore_StickerPackReference_Name.add(name: nameOffset, &builder) + offset = TelegramCore_StickerPackReference_Name.endStickerPackReference_Name(&builder, start: start) + case .animatedEmoji: + valueType = .stickerpackreferenceAnimatedemoji + let start = TelegramCore_StickerPackReference_AnimatedEmoji.startStickerPackReference_AnimatedEmoji(&builder) + offset = TelegramCore_StickerPackReference_AnimatedEmoji.endStickerPackReference_AnimatedEmoji(&builder, start: start) + case let .dice(emoji): + valueType = .stickerpackreferenceDice + let emojiOffset = builder.create(string: emoji) + let start = TelegramCore_StickerPackReference_Dice.startStickerPackReference_Dice(&builder) + TelegramCore_StickerPackReference_Dice.add(emoji: emojiOffset, &builder) + offset = TelegramCore_StickerPackReference_Dice.endStickerPackReference_Dice(&builder, start: start) + case .animatedEmojiAnimations: + valueType = .stickerpackreferenceAnimatedemojianimations + let start = TelegramCore_StickerPackReference_AnimatedEmojiAnimations.startStickerPackReference_AnimatedEmojiAnimations(&builder) + offset = TelegramCore_StickerPackReference_AnimatedEmojiAnimations.endStickerPackReference_AnimatedEmojiAnimations(&builder, start: start) + case .premiumGifts: + valueType = .stickerpackreferencePremiumgifts + let start = TelegramCore_StickerPackReference_PremiumGifts.startStickerPackReference_PremiumGifts(&builder) + offset = TelegramCore_StickerPackReference_PremiumGifts.endStickerPackReference_PremiumGifts(&builder, start: start) + case .emojiGenericAnimations: + valueType = .stickerpackreferenceEmojigenericanimations + let start = TelegramCore_StickerPackReference_EmojiGenericAnimations.startStickerPackReference_EmojiGenericAnimations(&builder) + offset = TelegramCore_StickerPackReference_EmojiGenericAnimations.endStickerPackReference_EmojiGenericAnimations(&builder, start: start) + case .iconStatusEmoji: + valueType = .stickerpackreferenceIconstatusemoji + let start = TelegramCore_StickerPackReference_IconStatusEmoji.startStickerPackReference_IconStatusEmoji(&builder) + offset = TelegramCore_StickerPackReference_IconStatusEmoji.endStickerPackReference_IconStatusEmoji(&builder, start: start) + case .iconTopicEmoji: + valueType = .stickerpackreferenceIcontopicemoji + let start = TelegramCore_StickerPackReference_IconTopicEmoji.startStickerPackReference_IconTopicEmoji(&builder) + offset = TelegramCore_StickerPackReference_IconTopicEmoji.endStickerPackReference_IconTopicEmoji(&builder, start: start) + case .iconChannelStatusEmoji: + valueType = .stickerpackreferenceIconchannelstatusemoji + let start = TelegramCore_StickerPackReference_IconChannelStatusEmoji.startStickerPackReference_IconChannelStatusEmoji(&builder) + offset = TelegramCore_StickerPackReference_IconChannelStatusEmoji.endStickerPackReference_IconChannelStatusEmoji(&builder, start: start) + } + return TelegramCore_StickerPackReference.createStickerPackReference(&builder, valueType: valueType, valueOffset: offset) + } + public static func ==(lhs: StickerPackReference, rhs: StickerPackReference) -> Bool { switch lhs { case let .id(id, accessHash): @@ -217,9 +314,9 @@ public struct StickerMaskCoords: PostboxCoding, Equatable { public init(decoder: PostboxDecoder) { self.n = decoder.decodeInt32ForKey("n", orElse: 0) - self.x = decoder.decodeDoubleForKey("x", orElse: 0.0) - self.y = decoder.decodeDoubleForKey("y", orElse: 0.0) - self.zoom = decoder.decodeDoubleForKey("z", orElse: 0.0) + self.x = Double(Float32(decoder.decodeDoubleForKey("x", orElse: 0.0))) + self.y = Double(Float32(decoder.decodeDoubleForKey("y", orElse: 0.0))) + self.zoom = Double(Float32(decoder.decodeDoubleForKey("z", orElse: 0.0))) } public func encode(_ encoder: PostboxEncoder) { @@ -228,6 +325,13 @@ public struct StickerMaskCoords: PostboxCoding, Equatable { encoder.encodeDouble(self.y, forKey: "y") encoder.encodeDouble(self.zoom, forKey: "z") } + + init(flatBuffersObject: TelegramCore_StickerMaskCoords) { + self.n = flatBuffersObject.n + self.x = Double(flatBuffersObject.x) + self.y = Double(flatBuffersObject.y) + self.zoom = Double(flatBuffersObject.zoom) + } } public enum TelegramMediaFileAttribute: PostboxCoding, Equatable { @@ -262,7 +366,12 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable { duration = Double(decoder.decodeInt32ForKey("du", orElse: 0)) } - self = .Video(duration: duration, size: PixelDimensions(width: decoder.decodeInt32ForKey("w", orElse: 0), height: decoder.decodeInt32ForKey("h", orElse: 0)), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)), preloadSize: decoder.decodeOptionalInt32ForKey("prs"), coverTime: decoder.decodeOptionalDoubleForKey("ct"), videoCodec: decoder.decodeOptionalStringForKey("vc")) + var coverTime: Double? + if let coverTimeValue = decoder.decodeOptionalDoubleForKey("ct") { + coverTime = Double(Float32(coverTimeValue)) + } + + self = .Video(duration: Double(Float32(duration)), size: PixelDimensions(width: decoder.decodeInt32ForKey("w", orElse: 0), height: decoder.decodeInt32ForKey("h", orElse: 0)), flags: TelegramMediaVideoFlags(rawValue: decoder.decodeInt32ForKey("f", orElse: 0)), preloadSize: decoder.decodeOptionalInt32ForKey("prs"), coverTime: coverTime, videoCodec: decoder.decodeOptionalStringForKey("vc")) case typeAudio: let waveformBuffer = decoder.decodeBytesForKeyNoCopy("wf") var waveform: Data? @@ -363,6 +472,171 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable { } } } + + init(flatBuffersData data: Data) throws { + var byteBuffer = ByteBuffer(data: data) + let flatBuffersObject: TelegramCore_TelegramMediaFileAttribute = try getCheckedRoot(byteBuffer: &byteBuffer) + try self.init(flatBuffersObject: flatBuffersObject) + } + + init(flatBuffersObject: TelegramCore_TelegramMediaFileAttribute) throws { + switch flatBuffersObject.valueType { + case .telegrammediafileattributeFilename: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_FileName.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .FileName(fileName: value.fileName) + case .telegrammediafileattributeSticker: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_Sticker.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .Sticker(displayText: value.displayText, packReference: try value.packReference.flatMap({ try StickerPackReference(flatBuffersObject: $0) }), maskData: value.maskData.flatMap({ StickerMaskCoords(flatBuffersObject: $0) })) + case .telegrammediafileattributeImagesize: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_ImageSize.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .ImageSize(size: PixelDimensions(width: value.width, height: value.height)) + case .telegrammediafileattributeAnimated: + self = .Animated + case .telegrammediafileattributeVideo: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_Video.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .Video(duration: Double(value.duration), size: PixelDimensions(width: value.width, height: value.height), flags: TelegramMediaVideoFlags(rawValue: value.flags), preloadSize: value.preloadSize == 0 ? nil : value.preloadSize, coverTime: value.coverTime == 0.0 ? nil : Double(value.coverTime), videoCodec: value.videoCodec) + case .telegrammediafileattributeAudio: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_Audio.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .Audio(isVoice: value.isVoice, duration: Int(value.duration), title: value.title, performer: value.performer, waveform: value.waveform.isEmpty ? nil : Data(value.waveform)) + case .telegrammediafileattributeHaslinkedstickers: + self = .HasLinkedStickers + case .telegrammediafileattributeHintfileislarge: + self = .hintFileIsLarge + case .telegrammediafileattributeHintisvalidated: + self = .hintIsValidated + case .telegrammediafileattributeNopremium: + self = .NoPremium + case .none_: + throw FlatBuffersError.missingRequiredField + case .telegrammediafileattributeCustomemoji: + guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_CustomEmoji.self) else { + throw FlatBuffersError.missingRequiredField + } + self = .CustomEmoji(isPremium: value.isPremium, isSingleColor: value.isSingleColor, alt: value.alt, packReference: try value.packReference.flatMap({ try StickerPackReference(flatBuffersObject: $0) })) + } + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let valueType: TelegramCore_TelegramMediaFileAttribute_Value + let offset: Offset + + switch self { + case let .FileName(fileName): + valueType = .telegrammediafileattributeFilename + let fileNameOffset = builder.create(string: fileName) + let start = TelegramCore_TelegramMediaFileAttribute_FileName.startTelegramMediaFileAttribute_FileName(&builder) + TelegramCore_TelegramMediaFileAttribute_FileName.add(fileName: fileNameOffset, &builder) + offset = TelegramCore_TelegramMediaFileAttribute_FileName.endTelegramMediaFileAttribute_FileName(&builder, start: start) + case let .Sticker(displayText, packReference, maskData): + valueType = .telegrammediafileattributeSticker + let displayTextOffset = builder.create(string: displayText) + + let packReferenceOffset = packReference.flatMap { + return $0.encodeToFlatBuffers(builder: &builder) + } + let maskDataOffset = maskData.flatMap { maskData -> Offset in + let start = TelegramCore_StickerMaskCoords.startStickerMaskCoords(&builder) + TelegramCore_StickerMaskCoords.add(n: maskData.n, &builder) + TelegramCore_StickerMaskCoords.add(x: Float32(maskData.x), &builder) + TelegramCore_StickerMaskCoords.add(y: Float32(maskData.y), &builder) + TelegramCore_StickerMaskCoords.add(zoom: Float32(maskData.zoom), &builder) + return TelegramCore_StickerMaskCoords.endStickerMaskCoords(&builder, start: start) + } + let start = TelegramCore_TelegramMediaFileAttribute_Sticker.startTelegramMediaFileAttribute_Sticker(&builder) + TelegramCore_TelegramMediaFileAttribute_Sticker.add(displayText: displayTextOffset, &builder) + if let packReferenceOffset { + TelegramCore_TelegramMediaFileAttribute_Sticker.add(packReference: packReferenceOffset, &builder) + } + if let maskDataOffset { + TelegramCore_TelegramMediaFileAttribute_Sticker.add(maskData: maskDataOffset, &builder) + } + offset = TelegramCore_TelegramMediaFileAttribute_Sticker.endTelegramMediaFileAttribute_Sticker(&builder, start: start) + case let .ImageSize(size): + valueType = .telegrammediafileattributeImagesize + let start = TelegramCore_TelegramMediaFileAttribute_ImageSize.startTelegramMediaFileAttribute_ImageSize(&builder) + TelegramCore_TelegramMediaFileAttribute_ImageSize.add(width: size.width, &builder) + TelegramCore_TelegramMediaFileAttribute_ImageSize.add(height: size.height, &builder) + offset = TelegramCore_TelegramMediaFileAttribute_ImageSize.endTelegramMediaFileAttribute_ImageSize(&builder, start: start) + case .Animated: + valueType = .telegrammediafileattributeAnimated + let start = TelegramCore_TelegramMediaFileAttribute_Animated.startTelegramMediaFileAttribute_Animated(&builder) + offset = TelegramCore_TelegramMediaFileAttribute_Animated.endTelegramMediaFileAttribute_Animated(&builder, start: start) + case let .Video(duration, size, flags, preloadSize, coverTime, videoCodec): + valueType = .telegrammediafileattributeVideo + let videoCodecOffset = videoCodec.flatMap { builder.create(string: $0) } + let start = TelegramCore_TelegramMediaFileAttribute_Video.startTelegramMediaFileAttribute_Video(&builder) + + TelegramCore_TelegramMediaFileAttribute_Video.add(duration: Float32(duration), &builder) + TelegramCore_TelegramMediaFileAttribute_Video.add(width: size.width, &builder) + TelegramCore_TelegramMediaFileAttribute_Video.add(height: size.height, &builder) + TelegramCore_TelegramMediaFileAttribute_Video.add(flags: flags.rawValue, &builder) + TelegramCore_TelegramMediaFileAttribute_Video.add(preloadSize: preloadSize ?? 0, &builder) + TelegramCore_TelegramMediaFileAttribute_Video.add(coverTime: Float32(coverTime ?? 0.0), &builder) + if let videoCodecOffset { + TelegramCore_TelegramMediaFileAttribute_Video.add(videoCodec: videoCodecOffset, &builder)} + offset = TelegramCore_TelegramMediaFileAttribute_Video.endTelegramMediaFileAttribute_Video(&builder, start: start) + case let .Audio(isVoice, duration, title, performer, waveform): + valueType = .telegrammediafileattributeAudio + let titleOffset = title.flatMap { builder.create(string: $0) } + let performerOffset = performer.flatMap { builder.create(string: $0) } + let waveformOffset = waveform.flatMap { builder.createVector(bytes: $0) } + let start = TelegramCore_TelegramMediaFileAttribute_Audio.startTelegramMediaFileAttribute_Audio(&builder) + TelegramCore_TelegramMediaFileAttribute_Audio.add(isVoice: isVoice, &builder) + TelegramCore_TelegramMediaFileAttribute_Audio.add(duration: Int32(duration), &builder) + if let titleOffset { + TelegramCore_TelegramMediaFileAttribute_Audio.add(title: titleOffset, &builder) + } + if let performerOffset { + TelegramCore_TelegramMediaFileAttribute_Audio.add(performer: performerOffset, &builder) + } + if let waveformOffset { + TelegramCore_TelegramMediaFileAttribute_Audio.addVectorOf(waveform: waveformOffset, &builder) + } + offset = TelegramCore_TelegramMediaFileAttribute_Audio.endTelegramMediaFileAttribute_Audio(&builder, start: start) + case .HasLinkedStickers: + valueType = .telegrammediafileattributeHaslinkedstickers + let start = TelegramCore_TelegramMediaFileAttribute_HasLinkedStickers.startTelegramMediaFileAttribute_HasLinkedStickers(&builder) + offset = TelegramCore_TelegramMediaFileAttribute_HasLinkedStickers.endTelegramMediaFileAttribute_HasLinkedStickers(&builder, start: start) + case .hintFileIsLarge: + valueType = .telegrammediafileattributeHintfileislarge + let start = TelegramCore_TelegramMediaFileAttribute_HintFileIsLarge.startTelegramMediaFileAttribute_HintFileIsLarge(&builder) + offset = TelegramCore_TelegramMediaFileAttribute_HintFileIsLarge.endTelegramMediaFileAttribute_HintFileIsLarge(&builder, start: start) + case .hintIsValidated: + valueType = .telegrammediafileattributeHintisvalidated + let start = TelegramCore_TelegramMediaFileAttribute_HintIsValidated.startTelegramMediaFileAttribute_HintIsValidated(&builder) + offset = TelegramCore_TelegramMediaFileAttribute_HintIsValidated.endTelegramMediaFileAttribute_HintIsValidated(&builder, start: start) + case .NoPremium: + valueType = .telegrammediafileattributeNopremium + let start = TelegramCore_TelegramMediaFileAttribute_NoPremium.startTelegramMediaFileAttribute_NoPremium(&builder) + offset = TelegramCore_TelegramMediaFileAttribute_NoPremium.endTelegramMediaFileAttribute_NoPremium(&builder, start: start) + case let .CustomEmoji(isPremium, isSingleColor, alt, packReference): + valueType = .telegrammediafileattributeCustomemoji + let altOffset = builder.create(string: alt) + let packReferenceOffset = packReference.flatMap { + return $0.encodeToFlatBuffers(builder: &builder) + } + let start = TelegramCore_TelegramMediaFileAttribute_CustomEmoji.startTelegramMediaFileAttribute_CustomEmoji(&builder) + TelegramCore_TelegramMediaFileAttribute_CustomEmoji.add(isPremium: isPremium, &builder) + TelegramCore_TelegramMediaFileAttribute_CustomEmoji.add(isSingleColor: isSingleColor, &builder) + TelegramCore_TelegramMediaFileAttribute_CustomEmoji.add(alt: altOffset, &builder) + if let packReferenceOffset { + TelegramCore_TelegramMediaFileAttribute_CustomEmoji.add(packReference: packReferenceOffset, &builder) + } + offset = TelegramCore_TelegramMediaFileAttribute_CustomEmoji.endTelegramMediaFileAttribute_CustomEmoji(&builder, start: start) + } + + return TelegramCore_TelegramMediaFileAttribute.createTelegramMediaFileAttribute(&builder, valueType: valueType, valueOffset: offset) + } } public enum TelegramMediaFileReference: PostboxCoding, Equatable { @@ -422,6 +696,23 @@ public final class TelegramMediaFile: Media, Equatable, Codable { encoder.encodeObject(self.resource, forKey: "r") } + public init(flatBuffersObject: TelegramCore_VideoThumbnail) throws { + self.dimensions = PixelDimensions(width: flatBuffersObject.width, height: flatBuffersObject.height) + self.resource = try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject.resource) + } + + public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let resourceOffset = TelegramMediaResource_serialize(resource: self.resource, flatBuffersBuilder: &builder)! + + let start = TelegramCore_VideoThumbnail.startVideoThumbnail(&builder) + + TelegramCore_VideoThumbnail.add(width: self.dimensions.width, &builder) + TelegramCore_VideoThumbnail.add(height: self.dimensions.height, &builder) + TelegramCore_VideoThumbnail.add(resource: resourceOffset, &builder) + + return TelegramCore_VideoThumbnail.endVideoThumbnail(&builder, start: start) + } + public static func ==(lhs: VideoThumbnail, rhs: VideoThumbnail) -> Bool { if lhs === rhs { return true @@ -446,7 +737,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable { public let mimeType: String public let size: Int64? public let attributes: [TelegramMediaFileAttribute] - public let alternativeRepresentations: [Media] + public let alternativeRepresentations: [TelegramMediaFile] public let peerIds: [PeerId] = [] public var id: MediaId? { @@ -477,7 +768,7 @@ public final class TelegramMediaFile: Media, Equatable, Codable { mimeType: String, size: Int64?, attributes: [TelegramMediaFileAttribute], - alternativeRepresentations: [Media] + alternativeRepresentations: [TelegramMediaFile] ) { self.fileId = fileId self.partialReference = partialReference @@ -510,12 +801,20 @@ public final class TelegramMediaFile: Media, Equatable, Codable { } self.attributes = decoder.decodeObjectArrayForKey("at") if let altMedia = try? decoder.decodeObjectArrayWithCustomDecoderForKey("arep", decoder: { d in - return d.decodeRootObject() as! Media + return d.decodeRootObject() }) { - self.alternativeRepresentations = altMedia + self.alternativeRepresentations = altMedia.compactMap { $0 as? TelegramMediaFile } } else { self.alternativeRepresentations = [] } + + /*#if DEBUG + let fbData = self.encodeToFlatBuffersData() + var byteBuffer = ByteBuffer(data: fbData) + let flatBuffersObject: TelegramCore_TelegramMediaFile = try! getCheckedRoot(byteBuffer: &byteBuffer) + let fbObject = try! TelegramMediaFile(flatBuffersObject: flatBuffersObject) + assert(self == fbObject) + #endif*/ } public func encode(_ encoder: PostboxEncoder) { @@ -580,6 +879,89 @@ public final class TelegramMediaFile: Media, Equatable, Codable { try container.encode(postboxEncoder.makeData(), forKey: .data) } + public func encodeToFlatBuffersData() -> Data { + var builder = FlatBufferBuilder(initialSize: 1024) + let value = self.encodeToFlatBuffers(builder: &builder) + builder.finish(offset: value) + return builder.data + } + + public init(flatBuffersObject: TelegramCore_TelegramMediaFile) throws { + self.fileId = MediaId(namespace: flatBuffersObject.fileId.namespace, id: flatBuffersObject.fileId.id) + self.partialReference = try flatBuffersObject.partialReference.flatMap { try PartialMediaReference(flatBuffersObject: $0 ) } + self.resource = try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject.resource) + self.previewRepresentations = try (0 ..< flatBuffersObject.previewRepresentationsCount).map { i in + return try TelegramMediaImageRepresentation(flatBuffersObject: flatBuffersObject.previewRepresentations(at: i)!) + } + self.videoThumbnails = try (0 ..< flatBuffersObject.videoThumbnailsCount).map { i in + return try VideoThumbnail(flatBuffersObject: flatBuffersObject.videoThumbnails(at: i)!) + } + self.videoCover = try flatBuffersObject.videoCover.flatMap { try TelegramMediaImage(flatBuffersObject: $0) } + self.immediateThumbnailData = flatBuffersObject.immediateThumbnailData.isEmpty ? nil : Data(flatBuffersObject.immediateThumbnailData) + self.mimeType = flatBuffersObject.mimeType + self.size = flatBuffersObject.size == Int64.min ? nil : flatBuffersObject.size + self.attributes = try (0 ..< flatBuffersObject.attributesCount).map { i in + return try TelegramMediaFileAttribute(flatBuffersObject: flatBuffersObject.attributes(at: i)!) + } + self.alternativeRepresentations = try (0 ..< flatBuffersObject.alternativeRepresentationsCount).map { i in + return try TelegramMediaFile(flatBuffersObject: flatBuffersObject.alternativeRepresentations(at: i)!) + } + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let partialReferenceOffset = self.partialReference.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + + let resourceOffset = TelegramMediaResource_serialize(resource: self.resource, flatBuffersBuilder: &builder)! + + let previewRepresentationsOffsets = self.previewRepresentations.map { attribute in + return attribute.encodeToFlatBuffers(builder: &builder) + } + let previewRepresentationsOffset = builder.createVector(ofOffsets: previewRepresentationsOffsets, len: previewRepresentationsOffsets.count) + + let videoThumbnailsOffsets = self.videoThumbnails.map { videoThumbnail in + return videoThumbnail.encodeToFlatBuffers(builder: &builder) + } + let videoThumbnailsOffset = builder.createVector(ofOffsets: videoThumbnailsOffsets, len: videoThumbnailsOffsets.count) + + let videoCoverOffset = self.videoCover.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + + let immediateThumbnailDataOffset = self.immediateThumbnailData.flatMap { builder.createVector(bytes: $0) } + + let mimeTypeOffset = builder.create(string: self.mimeType) + + let attributesOffsets = self.attributes.map { attribute in + return attribute.encodeToFlatBuffers(builder: &builder) + } + let attributesOffset = builder.createVector(ofOffsets: attributesOffsets, len: attributesOffsets.count) + + let alternativeRepresentationsOffsets = self.alternativeRepresentations.map { alternativeRepresentation in + return alternativeRepresentation.encodeToFlatBuffers(builder: &builder) + } + let alternativeRepresentationsOffset = builder.createVector(ofOffsets: alternativeRepresentationsOffsets, len: alternativeRepresentationsOffsets.count) + + let start = TelegramCore_TelegramMediaFile.startTelegramMediaFile(&builder) + + TelegramCore_TelegramMediaFile.add(fileId: TelegramCore_MediaId(namespace: self.fileId.namespace, id: self.fileId.id), &builder) + if let partialReferenceOffset { + TelegramCore_TelegramMediaFile.add(partialReference: partialReferenceOffset, &builder) + } + TelegramCore_TelegramMediaFile.add(resource: resourceOffset, &builder) + TelegramCore_TelegramMediaFile.addVectorOf(previewRepresentations: previewRepresentationsOffset, &builder) + TelegramCore_TelegramMediaFile.addVectorOf(videoThumbnails: videoThumbnailsOffset, &builder) + if let immediateThumbnailDataOffset { + TelegramCore_TelegramMediaFile.addVectorOf(immediateThumbnailData: immediateThumbnailDataOffset, &builder) + } + if let videoCoverOffset { + TelegramCore_TelegramMediaFile.add(videoCover: videoCoverOffset, &builder) + } + TelegramCore_TelegramMediaFile.add(mimeType: mimeTypeOffset, &builder) + TelegramCore_TelegramMediaFile.add(size: self.size ?? Int64.min, &builder) + TelegramCore_TelegramMediaFile.addVectorOf(attributes: attributesOffset, &builder) + TelegramCore_TelegramMediaFile.addVectorOf(alternativeRepresentations: alternativeRepresentationsOffset, &builder) + + return TelegramCore_TelegramMediaFile.endTelegramMediaFile(&builder, start: start) + } + public var fileName: String? { get { for attribute in self.attributes { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaImage.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaImage.swift index c16f7d8f6d..c20d8217a4 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaImage.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaImage.swift @@ -1,5 +1,7 @@ import Foundation import Postbox +import FlatBuffers +import FlatSerialization public enum TelegramMediaImageReferenceDecodingError: Error { case generic @@ -54,6 +56,31 @@ public enum TelegramMediaImageReference: PostboxCoding, Equatable { try container.encode(postboxEncoder.makeData(), forKey: .data) } + public init(flatBuffersObject: TelegramCore_TelegramMediaImageReference) throws { + self = .cloud( + imageId: flatBuffersObject.imageId, + accessHash: flatBuffersObject.accessHash, + fileReference: flatBuffersObject.fileReference.isEmpty ? nil : Data(flatBuffersObject.fileReference) + ) + } + + public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + switch self { + case let .cloud(imageId, accessHash, fileReference): + let fileReferenceOffset = fileReference.flatMap { builder.createVector(bytes: $0) } + + let start = TelegramCore_TelegramMediaImageReference.startTelegramMediaImageReference(&builder) + + TelegramCore_TelegramMediaImageReference.add(imageId: imageId, &builder) + TelegramCore_TelegramMediaImageReference.add(accessHash: accessHash, &builder) + if let fileReferenceOffset { + TelegramCore_TelegramMediaImageReference.addVectorOf(fileReference: fileReferenceOffset, &builder) + } + + return TelegramCore_TelegramMediaImageReference.endTelegramMediaImageReference(&builder, start: start) + } + } + public static func ==(lhs: TelegramMediaImageReference, rhs: TelegramMediaImageReference) -> Bool { switch lhs { case let .cloud(imageId, accessHash, fileReference): @@ -99,7 +126,7 @@ public final class TelegramMediaImage: Media, Equatable, Codable { public init(decoder: PostboxDecoder) { self.dimensions = PixelDimensions(width: decoder.decodeInt32ForKey("w", orElse: 0), height: decoder.decodeInt32ForKey("h", orElse: 0)) self.resource = decoder.decodeObjectForKey("r") as! TelegramMediaResource - self.startTimestamp = decoder.decodeOptionalDoubleForKey("s") + self.startTimestamp = decoder.decodeOptionalDoubleForKey("s").flatMap({ Double(Float32($0)) }) } public func encode(_ encoder: PostboxEncoder) { @@ -113,6 +140,29 @@ public final class TelegramMediaImage: Media, Equatable, Codable { } } + public init(flatBuffersObject: TelegramCore_VideoRepresentation) throws { + self.dimensions = PixelDimensions(width: flatBuffersObject.width, height: flatBuffersObject.height) + self.resource = try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject.resource) + if flatBuffersObject.startTimestamp != -1.0 { + self.startTimestamp = Double(flatBuffersObject.startTimestamp) + } else { + self.startTimestamp = nil + } + } + + public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let resourceOffset = TelegramMediaResource_serialize(resource: self.resource, flatBuffersBuilder: &builder)! + + let start = TelegramCore_VideoRepresentation.startVideoRepresentation(&builder) + + TelegramCore_VideoRepresentation.add(width: self.dimensions.width, &builder) + TelegramCore_VideoRepresentation.add(height: self.dimensions.height, &builder) + TelegramCore_VideoRepresentation.add(resource: resourceOffset, &builder) + TelegramCore_VideoRepresentation.add(startTimestamp: Float32(self.startTimestamp ?? -1.0), &builder) + + return TelegramCore_VideoRepresentation.endVideoRepresentation(&builder, start: start) + } + public static func ==(lhs: VideoRepresentation, rhs: VideoRepresentation) -> Bool { if lhs === rhs { return true @@ -165,6 +215,52 @@ public final class TelegramMediaImage: Media, Equatable, Codable { encoder.encodeInt32Array(self.backgroundColors, forKey: "b") } + init(flatBuffersObject: TelegramCore_EmojiMarkup) throws { + switch flatBuffersObject.contentType { + case .emojimarkupContentEmoji: + guard let value = flatBuffersObject.content(type: TelegramCore_EmojiMarkup_Content_Emoji.self) else { + throw FlatBuffersError.missingRequiredField + } + self.content = .emoji(fileId: value.fileId) + case .emojimarkupContentSticker: + guard let value = flatBuffersObject.content(type: TelegramCore_EmojiMarkup_Content_Sticker.self) else { + throw FlatBuffersError.missingRequiredField + } + self.content = .sticker(packReference: try StickerPackReference(flatBuffersObject: value.packReference), fileId: value.fileId) + case .none_: + throw FlatBuffersError.missingRequiredField + } + + self.backgroundColors = flatBuffersObject.backgroundColors + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let contentOffset: Offset + let contentType: TelegramCore_EmojiMarkup_Content + switch self.content { + case let .emoji(fileId): + contentType = .emojimarkupContentEmoji + let start = TelegramCore_EmojiMarkup_Content_Emoji.startEmojiMarkup_Content_Emoji(&builder) + TelegramCore_EmojiMarkup_Content_Emoji.add(fileId: fileId, &builder) + contentOffset = TelegramCore_EmojiMarkup_Content_Emoji.endEmojiMarkup_Content_Emoji(&builder, start: start) + case let .sticker(packReference, fileId): + contentType = .emojimarkupContentSticker + let packReferenceOffset = packReference.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_EmojiMarkup_Content_Sticker.startEmojiMarkup_Content_Sticker(&builder) + TelegramCore_EmojiMarkup_Content_Sticker.add(packReference: packReferenceOffset, &builder) + TelegramCore_EmojiMarkup_Content_Sticker.add(fileId: fileId, &builder) + contentOffset = TelegramCore_EmojiMarkup_Content_Sticker.endEmojiMarkup_Content_Sticker(&builder, start: start) + } + + let backgroundColorsOffset = builder.createVector(self.backgroundColors) + + let start = TelegramCore_EmojiMarkup.startEmojiMarkup(&builder) + TelegramCore_EmojiMarkup.add(contentType: contentType, &builder) + TelegramCore_EmojiMarkup.add(content: contentOffset, &builder) + TelegramCore_EmojiMarkup.addVectorOf(backgroundColors: backgroundColorsOffset, &builder) + return TelegramCore_EmojiMarkup.endEmojiMarkup(&builder, start: start) + } + public static func ==(lhs: EmojiMarkup, rhs: EmojiMarkup) -> Bool { if lhs.content != rhs.content { return false @@ -267,6 +363,59 @@ public final class TelegramMediaImage: Media, Equatable, Codable { try container.encode(postboxEncoder.makeData(), forKey: .data) } + public init(flatBuffersObject: TelegramCore_TelegramMediaImage) throws { + self.imageId = MediaId(namespace: flatBuffersObject.imageId.namespace, id: flatBuffersObject.imageId.id) + self.representations = try (0 ..< flatBuffersObject.representationsCount).map { i in + return try TelegramMediaImageRepresentation(flatBuffersObject: flatBuffersObject.representations(at: i)!) + } + self.videoRepresentations = try (0 ..< flatBuffersObject.videoRepresentationsCount).map { i in + return try TelegramMediaImage.VideoRepresentation(flatBuffersObject: flatBuffersObject.videoRepresentations(at: i)!) + } + self.immediateThumbnailData = flatBuffersObject.immediateThumbnailData.isEmpty ? nil : Data(flatBuffersObject.immediateThumbnailData) + self.emojiMarkup = try flatBuffersObject.emojiMarkup.map { try EmojiMarkup(flatBuffersObject: $0) } + self.reference = try flatBuffersObject.reference.map { try TelegramMediaImageReference(flatBuffersObject: $0) } + self.partialReference = try flatBuffersObject.partialReference.map { try PartialMediaReference(flatBuffersObject: $0) } + self.flags = TelegramMediaImageFlags(rawValue: flatBuffersObject.flags) + } + + public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let representationsOffsets = self.representations.map { item in + return item.encodeToFlatBuffers(builder: &builder) + } + let representationsOffset = builder.createVector(ofOffsets: representationsOffsets, len: representationsOffsets.count) + + let videoRepresentationsOffsets = self.videoRepresentations.map { item in + return item.encodeToFlatBuffers(builder: &builder) + } + let videoRepresentationsOffset = builder.createVector(ofOffsets: videoRepresentationsOffsets, len: videoRepresentationsOffsets.count) + + let immediateThumbnailDataOffset = self.immediateThumbnailData.flatMap { builder.createVector(bytes: $0) } + let emojiMarkupOffset = self.emojiMarkup.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + let referenceOffset = self.reference.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + let partialReferenceOffset = self.partialReference.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + + let start = TelegramCore_TelegramMediaImage.startTelegramMediaImage(&builder) + + TelegramCore_TelegramMediaImage.add(imageId: TelegramCore_MediaId(namespace: self.imageId.namespace, id: self.imageId.id), &builder) + TelegramCore_TelegramMediaImage.addVectorOf(representations: representationsOffset, &builder) + TelegramCore_TelegramMediaImage.addVectorOf(videoRepresentations: videoRepresentationsOffset, &builder) + if let immediateThumbnailDataOffset { + TelegramCore_TelegramMediaImage.addVectorOf(immediateThumbnailData: immediateThumbnailDataOffset, &builder) + } + if let emojiMarkupOffset { + TelegramCore_TelegramMediaImage.add(emojiMarkup: emojiMarkupOffset, &builder) + } + if let referenceOffset { + TelegramCore_TelegramMediaImage.add(reference: referenceOffset, &builder) + } + if let partialReferenceOffset { + TelegramCore_TelegramMediaImage.add(partialReference: partialReferenceOffset, &builder) + } + TelegramCore_TelegramMediaImage.add(flags: self.flags.rawValue, &builder) + + return TelegramCore_TelegramMediaImage.endTelegramMediaImage(&builder, start: start) + } + public func representationForDisplayAtSize(_ size: PixelDimensions) -> TelegramMediaImageRepresentation? { if self.representations.count == 0 { return nil @@ -417,6 +566,44 @@ public final class TelegramMediaImageRepresentation: PostboxCoding, Equatable, C encoder.encodeInt32(self.typeHint.rawValue, forKey: "th") } + public init(flatBuffersObject: TelegramCore_TelegramMediaImageRepresentation) throws { + self.dimensions = PixelDimensions(width: flatBuffersObject.width, height: flatBuffersObject.height) + self.resource = try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject.resource) + self.progressiveSizes = flatBuffersObject.progressiveSizes + self.immediateThumbnailData = flatBuffersObject.immediateThumbnailData.isEmpty ? nil : Data(flatBuffersObject.immediateThumbnailData) + self.hasVideo = flatBuffersObject.hasVideo + self.isPersonal = flatBuffersObject.isPersonal + + switch flatBuffersObject.typeHint { + case .generic: + self.typeHint = .generic + case .animated: + self.typeHint = .animated + case .video: + self.typeHint = .video + } + } + + func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset { + let resourceOffset = TelegramMediaResource_serialize(resource: self.resource, flatBuffersBuilder: &builder)! + let progressiveSizesOffset = builder.createVector(self.progressiveSizes) + let immediateThumbnailDataOffset = self.immediateThumbnailData.flatMap { builder.createVector(bytes: $0) } + + let start = TelegramCore_TelegramMediaImageRepresentation.startTelegramMediaImageRepresentation(&builder) + + TelegramCore_TelegramMediaImageRepresentation.add(width: self.dimensions.width, &builder) + TelegramCore_TelegramMediaImageRepresentation.add(height: self.dimensions.height, &builder) + TelegramCore_TelegramMediaImageRepresentation.add(resource: resourceOffset, &builder) + TelegramCore_TelegramMediaImageRepresentation.addVectorOf(progressiveSizes: progressiveSizesOffset, &builder) + if let immediateThumbnailDataOffset { + TelegramCore_TelegramMediaImageRepresentation.addVectorOf(immediateThumbnailData: immediateThumbnailDataOffset, &builder) + } + TelegramCore_TelegramMediaImageRepresentation.add(hasVideo: self.hasVideo, &builder) + TelegramCore_TelegramMediaImageRepresentation.add(isPersonal: self.isPersonal, &builder) + + return TelegramCore_TelegramMediaImageRepresentation.endTelegramMediaImageRepresentation(&builder, start: start) + } + public var description: String { return "(\(Int(dimensions.width))x\(Int(dimensions.height)))" } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift index 1d87fe12af..de39e91f77 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/CollectCacheUsageStats.swift @@ -583,12 +583,10 @@ func _internal_reindexCacheInBackground(account: Account, lowImpact: Bool) -> Si } processResource(mediaMessages, file.resource, MediaResourceUserContentType(file: file)) for alternativeRepresentation in file.alternativeRepresentations { - if let alternativeRepresentation = alternativeRepresentation as? TelegramMediaFile { - for representation in alternativeRepresentation.previewRepresentations { - processResource(mediaMessages, representation.resource, MediaResourceUserContentType(file: file)) - } - processResource(mediaMessages, alternativeRepresentation.resource, MediaResourceUserContentType(file: file)) + for representation in alternativeRepresentation.previewRepresentations { + processResource(mediaMessages, representation.resource, MediaResourceUserContentType(file: file)) } + processResource(mediaMessages, alternativeRepresentation.resource, MediaResourceUserContentType(file: file)) } } else if let webpage = media as? TelegramMediaWebpage { if case let .Loaded(content) = webpage.content { diff --git a/submodules/TelegramUI/Components/EntityKeyboard/BUILD b/submodules/TelegramUI/Components/EntityKeyboard/BUILD index 3e7e6d2904..63377ffc5c 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/BUILD +++ b/submodules/TelegramUI/Components/EntityKeyboard/BUILD @@ -48,6 +48,8 @@ swift_library( "//submodules/lottie-ios:Lottie", "//submodules/TelegramUI/Components/Utils/GenerateStickerPlaceholderImage", "//submodules/TelegramUIPreferences", + "//submodules/TelegramCore/FlatBuffers", + "//submodules/TelegramCore/FlatSerialization", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift index be8bc4b441..3d3b7deaf0 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentSignals.swift @@ -7,6 +7,8 @@ import SwiftSignalKit import AnimationCache import MultiAnimationRenderer import TelegramNotices +import FlatBuffers +import FlatSerialization public extension EmojiPagerContentComponent { private static func hasPremium(context: AccountContext, chatPeerId: EnginePeer.Id?, premiumIfSavedMessages: Bool) -> Signal { @@ -1366,6 +1368,14 @@ public extension EmojiPagerContentComponent { continue } + #if DEBUG && false + let fbData = item.file.encodeToFlatBuffersData() + var byteBuffer = ByteBuffer(data: fbData) + let flatBuffersObject: TelegramCore_TelegramMediaFile = try! getCheckedRoot(byteBuffer: &byteBuffer) + let fbObject = try! TelegramMediaFile(flatBuffersObject: flatBuffersObject) + assert(item.file == fbObject) + #endif + var icon: EmojiPagerContentComponent.Item.Icon = .none if [.reaction(onlyTop: false), .quickReaction].contains(subject), !hasPremium { icon = .locked diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index dddca01936..9ec158b865 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -986,6 +986,8 @@ extension ChatControllerImpl { //effectiveCachedDataReady = .single(true) effectiveCachedDataReady = self.cachedDataReady.get() } + var measure_isFirstTime = true + let initTimestamp = self.initTimestamp self.ready.set(combineLatest(queue: .mainQueue(), self.chatDisplayNode.historyNode.historyState.get(), self._chatLocationInfoReady.get(), @@ -997,7 +999,16 @@ extension ChatControllerImpl { |> map { _, chatLocationInfoReady, cachedDataReady, _, wallpaperReady, presentationReady in return chatLocationInfoReady && cachedDataReady && wallpaperReady && presentationReady } - |> distinctUntilChanged) + |> distinctUntilChanged + |> beforeNext { value in + if measure_isFirstTime { + measure_isFirstTime = false + #if DEBUG + let deltaTime = (CFAbsoluteTimeGetCurrent() - initTimestamp) * 1000.0 + print("Chat controller init to ready: \(deltaTime) ms") + #endif + } + }) if self.context.sharedContext.immediateExperimentalUISettings.crashOnLongQueries { let _ = (self.ready.get() diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 91522c1bf0..056be32a06 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -627,6 +627,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var currentSendStarsUndoMessageId: EngineMessage.Id? var currentSendStarsUndoCount: Int = 0 + let initTimestamp: Double + public var alwaysShowSearchResultsAsList: Bool = false { didSet { self.presentationInterfaceState = self.presentationInterfaceState.updatedDisplayHistoryFilterAsList(self.alwaysShowSearchResultsAsList) @@ -675,6 +677,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G customChatNavigationStack: [EnginePeer.Id]? = nil, params: ChatControllerParams? = nil ) { + self.initTimestamp = CFAbsoluteTimeGetCurrent() + let _ = ChatControllerCount.modify { value in return value + 1 } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 01e1ae29e2..bb140f1581 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -733,8 +733,13 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto public var isReady: Signal { return self._isReady.get() } + private var didSetReady: Bool = false + + private let initTimestamp: Double public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal), chatLocation: ChatLocation, chatLocationContextHolder: Atomic, tag: HistoryViewInputTag?, source: ChatHistoryListSource, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal?, NoError>, mode: ChatHistoryListMode = .bubbles, rotated: Bool = false, isChatPreview: Bool, messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl?) { + self.initTimestamp = CFAbsoluteTimeGetCurrent() + var tag = tag if case .pinnedMessages = subject { tag = .tag(.pinned) @@ -1698,6 +1703,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } |> distinctUntilChanged + let startTime = CFAbsoluteTimeGetCurrent() + var measure_isFirstTime = true let messageViewQueue = Queue.mainQueue() let historyViewTransitionDisposable = combineLatest(queue: messageViewQueue, historyViewUpdate, @@ -1728,6 +1735,14 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto ).startStrict(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, preferredStoryHighQuality, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, availableReactions, availableMessageEffects, savedMessageTags, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId, translationState, maxReadStoryId, recommendedChannels, audioTranscriptionTrial, chatThemes, deviceContactsNumbers, contentSettings in let (historyAppearsCleared, pendingUnpinnedAllMessages, pendingRemovedMessages, currentlyPlayingMessageIdAndType, scrollToMessageId, chatHasBots, allAdMessages) = promises + if measure_isFirstTime { + measure_isFirstTime = false + #if DEBUG + let deltaTime = (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0 + print("Chat load time: \(deltaTime) ms") + #endif + } + func applyHole() { Queue.mainQueue().async { if let strongSelf = self { @@ -4051,6 +4066,14 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto strongSelf.dequeueHistoryViewTransitions() strongSelf._isReady.set(true) + + if !strongSelf.didSetReady { + strongSelf.didSetReady = true + #if DEBUG + let deltaTime = (CFAbsoluteTimeGetCurrent() - strongSelf.initTimestamp) * 1000.0 + print("Chat init to dequeue time: \(deltaTime) ms") + #endif + } } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoContent.swift index 1b3f218060..de1b5ca36b 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoContent.swift @@ -55,25 +55,24 @@ public final class HLSQualitySet { public init?(baseFile: FileMediaReference, codecConfiguration: HLSCodecConfiguration) { var qualityFiles: [Int: FileMediaReference] = [:] for alternativeRepresentation in baseFile.media.alternativeRepresentations { - if let alternativeFile = alternativeRepresentation as? TelegramMediaFile { - for attribute in alternativeFile.attributes { - if case let .Video(_, size, _, _, _, videoCodec) = attribute { - if let videoCodec, NativeVideoContent.isVideoCodecSupported(videoCodec: videoCodec, isHardwareAv1Supported: codecConfiguration.isHardwareAv1Supported, isSoftwareAv1Supported: codecConfiguration.isSoftwareAv1Supported) { - let key = Int(min(size.width, size.height)) - if let currentFile = qualityFiles[key] { - var currentCodec: String? - for attribute in currentFile.media.attributes { - if case let .Video(_, _, _, _, _, videoCodec) = attribute { - currentCodec = videoCodec - } - } - if let currentCodec, (currentCodec == "av1" || currentCodec == "av01") { - } else { - qualityFiles[key] = baseFile.withMedia(alternativeFile) + let alternativeFile = alternativeRepresentation + for attribute in alternativeFile.attributes { + if case let .Video(_, size, _, _, _, videoCodec) = attribute { + if let videoCodec, NativeVideoContent.isVideoCodecSupported(videoCodec: videoCodec, isHardwareAv1Supported: codecConfiguration.isHardwareAv1Supported, isSoftwareAv1Supported: codecConfiguration.isSoftwareAv1Supported) { + let key = Int(min(size.width, size.height)) + if let currentFile = qualityFiles[key] { + var currentCodec: String? + for attribute in currentFile.media.attributes { + if case let .Video(_, _, _, _, _, videoCodec) = attribute { + currentCodec = videoCodec } + } + if let currentCodec, (currentCodec == "av1" || currentCodec == "av01") { } else { qualityFiles[key] = baseFile.withMedia(alternativeFile) } + } else { + qualityFiles[key] = baseFile.withMedia(alternativeFile) } } } @@ -82,17 +81,16 @@ public final class HLSQualitySet { var playlistFiles: [Int: FileMediaReference] = [:] for alternativeRepresentation in baseFile.media.alternativeRepresentations { - if let alternativeFile = alternativeRepresentation as? TelegramMediaFile { - if alternativeFile.mimeType == "application/x-mpegurl" { - if let fileName = alternativeFile.fileName { - if fileName.hasPrefix("mtproto:") { - let fileIdString = String(fileName[fileName.index(fileName.startIndex, offsetBy: "mtproto:".count)...]) - if let fileId = Int64(fileIdString) { - for (quality, file) in qualityFiles { - if file.media.fileId.id == fileId { - playlistFiles[quality] = baseFile.withMedia(alternativeFile) - break - } + let alternativeFile = alternativeRepresentation + if alternativeFile.mimeType == "application/x-mpegurl" { + if let fileName = alternativeFile.fileName { + if fileName.hasPrefix("mtproto:") { + let fileIdString = String(fileName[fileName.index(fileName.startIndex, offsetBy: "mtproto:".count)...]) + if let fileId = Int64(fileIdString) { + for (quality, file) in qualityFiles { + if file.media.fileId.id == fileId { + playlistFiles[quality] = baseFile.withMedia(alternativeFile) + break } } } diff --git a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift index f934d0c92e..b6d93d145d 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/NativeVideoContent.swift @@ -73,10 +73,8 @@ public final class NativeVideoContent: UniversalVideoContent { public static func isHLSVideo(file: TelegramMediaFile) -> Bool { for alternativeRepresentation in file.alternativeRepresentations { - if let alternativeFile = alternativeRepresentation as? TelegramMediaFile { - if alternativeFile.mimeType == "application/x-mpegurl" { - return true - } + if alternativeRepresentation.mimeType == "application/x-mpegurl" { + return true } } return false