Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2025-02-22 19:17:46 +04:00
commit c39fdb4463
63 changed files with 2927 additions and 671 deletions

2
.gitignore vendored
View File

@ -68,4 +68,4 @@ build-input/*
submodules/OpusBinding/SharedHeaders/*
submodules/FFMpegBinding/SharedHeaders/*
submodules/OpenSSLEncryptionProvider/SharedHeaders/*
buildServer.json

19
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "sweetpad-lldb",
"request": "attach",
"name": "Attach to running app (SweetPad)",
"preLaunchTask": "sweetpad: launch",
"codelldbAttributes": {
"initCommands": [
"command source ~/.lldbinit-Xcode"
]
}
}
]
}

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"sweetpad.build.xcodeWorkspacePath": "Telegram/Telegram.xcodeproj/project.xcworkspace",
"lldb.library": "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Versions/A/LLDB",
"lldb.launch.expressions": "native"
}

19
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "sweetpad",
"action": "launch",
"problemMatcher": [
"$sweetpad-watch", // ! Required for debugging
"$sweetpad-xcodebuild-default",
"$sweetpad-xcbeautify-errors",
"$sweetpad-xcbeautify-warnings"
],
"label": "sweetpad: launch",
"detail": "Build and Launch the app",
"isBackground": true // ! Required for debugging
}
]
}

View File

@ -142,6 +142,8 @@ public protocol MediaManager: AnyObject {
var universalVideoManager: UniversalVideoManager { get }
var overlayMediaManager: OverlayMediaManager { get }
var currentPictureInPictureNode: AnyObject? { get set }
var globalMediaPlayerState: Signal<(Account, SharedMediaPlayerItemPlaybackStateOrLoading, MediaManagerPlayerType)?, NoError> { get }
var musicMediaPlayerState: Signal<(Account, SharedMediaPlayerItemPlaybackStateOrLoading, MediaManagerPlayerType)?, NoError> { get }
var activeGlobalMediaPlayerAccountId: Signal<(AccountRecordId, Bool)?, NoError> { get }

View File

@ -1287,7 +1287,7 @@ public class GalleryController: ViewController, StandalonePresentableController,
self.dismiss(forceAway: false)
}
private func dismiss(forceAway: Bool) {
func dismiss(forceAway: Bool) {
var animatedOutNode = true
var animatedOutInterface = false
@ -1340,7 +1340,7 @@ public class GalleryController: ViewController, StandalonePresentableController,
}, pushController: { [weak self] c in
self?.baseNavigationController?.pushViewController(c)
self?.dismiss(forceAway: true)
}, dismissController: { [weak self] in
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { [weak self] controller, ready in
if let strongSelf = self {
@ -1403,32 +1403,51 @@ public class GalleryController: ViewController, StandalonePresentableController,
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
self.galleryNode.beginCustomDismiss = { [weak self] simpleAnimation in
self.galleryNode.beginCustomDismiss = { [weak self] animationType in
if let strongSelf = self {
strongSelf.actionInteraction?.updateCanReadHistory(true)
strongSelf._hiddenMedia.set(.single(nil))
let animatedOutNode = !simpleAnimation
if let chatController = strongSelf.baseNavigationController?.topViewController as? ChatController {
chatController.updatePushedTransition(0.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0)))
if let hiddenMediaManagerIndex = strongSelf.hiddenMediaManagerIndex {
strongSelf.hiddenMediaManagerIndex = nil
strongSelf.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
}
strongSelf.galleryNode.animateOut(animateContent: animatedOutNode, completion: {
})
switch animationType {
case .default, .simpleAnimation:
let animatedOutNode = animationType != .simpleAnimation
if let chatController = strongSelf.baseNavigationController?.topViewController as? ChatController {
chatController.updatePushedTransition(0.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0)))
}
strongSelf.galleryNode.animateOut(animateContent: animatedOutNode, completion: {
})
case .pip:
break
}
}
}
self.galleryNode.completeCustomDismiss = { [weak self] isPictureInPicture in
guard let self else {
return
}
if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex {
self.hiddenMediaManagerIndex = nil
self.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
}
if isPictureInPicture {
if let chatController = self?.baseNavigationController?.topViewController as? ChatController {
if let chatController = self.baseNavigationController?.topViewController as? ChatController {
chatController.updatePushedTransition(0.0, transition: .animated(duration: 0.45, curve: .customSpring(damping: 180.0, initialVelocity: 0.0)))
}
} else {
self?._hiddenMedia.set(.single(nil))
self._hiddenMedia.set(.single(nil))
}
self?.presentingViewController?.dismiss(animated: false, completion: nil)
self.presentingViewController?.dismiss(animated: false, completion: nil)
}
self.galleryNode.controlsVisibilityChanged = { [weak self] visible in
@ -1666,6 +1685,22 @@ public class GalleryController: ViewController, StandalonePresentableController,
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex {
self.hiddenMediaManagerIndex = nil
self.context.sharedContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
}
let context = self.context
let mediaManager = context.sharedContext.mediaManager
self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get()
|> map { messageIdAndMedia in
if let (messageId, media) = messageIdAndMedia {
return .chat(context.account.id, messageId, media)
} else {
return nil
}
})
var nodeAnimatesItself = false
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
@ -1851,4 +1886,23 @@ public class GalleryController: ViewController, StandalonePresentableController,
keyShortcuts.append(contentsOf: itemNodeShortcuts)
return keyShortcuts
}
public static func maybeExpandPIP(context: AccountContext, messageId: EngineMessage.Id) -> Bool {
guard let currentPictureInPictureNode = context.sharedContext.mediaManager.currentPictureInPictureNode as? UniversalVideoGalleryItemNode else {
return false
}
guard let item = currentPictureInPictureNode.item else {
return false
}
guard case let .message(message, _) = item.contentInfo else {
return false
}
if message.id != messageId {
return false
}
currentPictureInPictureNode.expandPIP()
return true
}
}

View File

@ -8,6 +8,12 @@ import AccountContext
import UndoUI
open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDelegate {
public enum CustomDismissType {
case `default`
case simpleAnimation
case pip
}
private let context: AccountContext
public var statusBar: StatusBar?
@ -27,7 +33,7 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture
public var scrollView: UIScrollView
public var pager: GalleryPagerNode
public var beginCustomDismiss: (Bool) -> Void = { _ in }
public var beginCustomDismiss: (GalleryControllerNode.CustomDismissType) -> Void = { _ in }
public var completeCustomDismiss: (Bool) -> Void = { _ in }
public var baseNavigationController: () -> NavigationController? = { return nil }
public var galleryController: () -> ViewController? = { return nil }
@ -128,9 +134,9 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture
}
}
self.pager.beginCustomDismiss = { [weak self] simpleAnimation in
self.pager.beginCustomDismiss = { [weak self] animationType in
if let strongSelf = self {
strongSelf.beginCustomDismiss(simpleAnimation)
strongSelf.beginCustomDismiss(animationType)
}
}

View File

@ -30,7 +30,7 @@ open class GalleryItemNode: ASDisplayNode {
public var controlsVisibility: () -> Bool = { return true }
public var updateOrientation: (UIInterfaceOrientation) -> Void = { _ in }
public var dismiss: () -> Void = { }
public var beginCustomDismiss: (Bool) -> Void = { _ in }
public var beginCustomDismiss: (GalleryControllerNode.CustomDismissType) -> Void = { _ in }
public var completeCustomDismiss: (Bool) -> Void = { _ in }
public var baseNavigationController: () -> NavigationController? = { return nil }
public var galleryController: () -> ViewController? = { return nil }

View File

@ -117,7 +117,7 @@ public final class GalleryPagerNode: ASDisplayNode, ASScrollViewDelegate, ASGest
public var controlsVisibility: () -> Bool = { return true }
public var updateOrientation: (UIInterfaceOrientation) -> Void = { _ in }
public var dismiss: () -> Void = { }
public var beginCustomDismiss: (Bool) -> Void = { _ in }
public var beginCustomDismiss: (GalleryControllerNode.CustomDismissType) -> Void = { _ in }
public var completeCustomDismiss: (Bool) -> Void = { _ in }
public var baseNavigationController: () -> NavigationController? = { return nil }
public var galleryController: () -> ViewController? = { return nil }

View File

@ -690,7 +690,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
if let message = self.message {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor)}, action: { [weak self] _, f in
if let self, let peer, let navigationController = self.baseNavigationController() {
self.beginCustomDismiss(true)
self.beginCustomDismiss(.simpleAnimation)
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: .message(id: .id(message.id), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false)))
@ -722,7 +722,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
if let peer, let message = self.message, canSendMessagesToPeer(peer._asPeer()) {
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuReply, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reply"), color: theme.contextMenu.primaryColor)}, action: { [weak self] _, f in
if let self, let navigationController = self.baseNavigationController() {
self.beginCustomDismiss(true)
self.beginCustomDismiss(.simpleAnimation)
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: .message(id: .id(message.id), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: true)))

View File

@ -730,309 +730,6 @@ final class SettingsHeaderButton: HighlightableButtonNode {
}
}
@available(iOS 15.0, *)
private final class PictureInPictureContentImpl: NSObject, PictureInPictureContent, AVPictureInPictureControllerDelegate {
private final class PlaybackDelegate: NSObject, AVPictureInPictureSampleBufferPlaybackDelegate {
private let node: UniversalVideoNode
private var statusDisposable: Disposable?
private var status: MediaPlayerStatus?
weak var pictureInPictureController: AVPictureInPictureController?
private var previousIsPlaying = false
init(node: UniversalVideoNode) {
self.node = node
super.init()
var invalidatedStateOnce = false
self.statusDisposable = (self.node.status
|> deliverOnMainQueue).start(next: { [weak self] status in
guard let strongSelf = self else {
return
}
strongSelf.status = status
if let status {
let isPlaying = status.status == .playing
if !invalidatedStateOnce {
invalidatedStateOnce = true
strongSelf.pictureInPictureController?.invalidatePlaybackState()
} else if strongSelf.previousIsPlaying != isPlaying {
strongSelf.previousIsPlaying = isPlaying
strongSelf.pictureInPictureController?.invalidatePlaybackState()
}
}
}).strict()
}
deinit {
self.statusDisposable?.dispose()
}
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) {
self.node.togglePlayPause()
}
public func pictureInPictureControllerTimeRangeForPlayback(_ pictureInPictureController: AVPictureInPictureController) -> CMTimeRange {
guard let status = self.status else {
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)))
}
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration - status.timestamp, preferredTimescale: CMTimeScale(30.0)))
}
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
guard let status = self.status else {
return false
}
switch status.status {
case .playing:
return false
case .buffering, .paused:
return true
}
}
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, didTransitionToRenderSize newRenderSize: CMVideoDimensions) {
}
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, skipByInterval skipInterval: CMTime, completion completionHandler: @escaping () -> Void) {
let node = self.node
let _ = (self.node.status
|> take(1)
|> deliverOnMainQueue).start(next: { [weak node] status in
if let node = node, let timestamp = status?.timestamp, let duration = status?.duration {
let nextTimestamp = timestamp + skipInterval.seconds
if nextTimestamp > duration {
node.seek(0.0)
node.pause()
} else {
node.seek(min(duration, nextTimestamp))
}
}
completionHandler()
})
}
public func pictureInPictureControllerShouldProhibitBackgroundAudioPlayback(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
return false
}
}
private weak var overlayController: OverlayMediaController?
private weak var mediaManager: MediaManager?
private var pictureInPictureController: AVPictureInPictureController?
private var contentDelegate: PlaybackDelegate?
private let node: UniversalVideoNode
private let willBegin: (PictureInPictureContentImpl) -> Void
private let didEnd: (PictureInPictureContentImpl) -> Void
private let expand: (@escaping () -> Void) -> Void
private var pictureInPictureTimer: SwiftSignalKit.Timer?
private var didExpand: Bool = false
private var hiddenMediaManagerIndex: Int?
private var messageRemovedDisposable: Disposable?
private var isNativePictureInPictureActiveDisposable: Disposable?
init(context: AccountContext, overlayController: OverlayMediaController, mediaManager: MediaManager, accountId: AccountRecordId, hiddenMedia: (MessageId, Media)?, videoNode: UniversalVideoNode, canSkip: Bool, willBegin: @escaping (PictureInPictureContentImpl) -> Void, didEnd: @escaping (PictureInPictureContentImpl) -> Void, expand: @escaping (@escaping () -> Void) -> Void) {
self.overlayController = overlayController
self.mediaManager = mediaManager
self.node = videoNode
self.willBegin = willBegin
self.didEnd = didEnd
self.expand = expand
self.node.setCanPlaybackWithoutHierarchy(true)
super.init()
if let videoLayer = videoNode.getVideoLayer() {
let contentDelegate = PlaybackDelegate(node: self.node)
self.contentDelegate = contentDelegate
let pictureInPictureController = AVPictureInPictureController(contentSource: AVPictureInPictureController.ContentSource(sampleBufferDisplayLayer: videoLayer, playbackDelegate: contentDelegate))
self.pictureInPictureController = pictureInPictureController
contentDelegate.pictureInPictureController = pictureInPictureController
pictureInPictureController.canStartPictureInPictureAutomaticallyFromInline = false
pictureInPictureController.requiresLinearPlayback = !canSkip
pictureInPictureController.delegate = self
self.pictureInPictureController = pictureInPictureController
let timer = SwiftSignalKit.Timer(timeout: 0.005, repeat: true, completion: { [weak self] in
guard let strongSelf = self, let pictureInPictureController = strongSelf.pictureInPictureController else {
return
}
if pictureInPictureController.isPictureInPicturePossible {
strongSelf.pictureInPictureTimer?.invalidate()
strongSelf.pictureInPictureTimer = nil
pictureInPictureController.startPictureInPicture()
}
}, queue: .mainQueue())
self.pictureInPictureTimer = timer
timer.start()
} else {
var currentIsNativePictureInPictureActive = false
self.isNativePictureInPictureActiveDisposable = (videoNode.isNativePictureInPictureActive
|> deliverOnMainQueue).startStrict(next: { [weak self] isNativePictureInPictureActive in
guard let self else {
return
}
if currentIsNativePictureInPictureActive == isNativePictureInPictureActive {
return
}
currentIsNativePictureInPictureActive = isNativePictureInPictureActive
if isNativePictureInPictureActive {
Queue.mainQueue().after(0.0, { [weak self] in
guard let self else {
return
}
self.willBegin(self)
if let overlayController = self.overlayController {
overlayController.setPictureInPictureContentHidden(content: self, isHidden: true)
}
self.didEnd(self)
})
} else {
self.expand { [weak self] in
guard let self else {
return
}
self.didExpand = true
if let overlayController = self.overlayController {
overlayController.setPictureInPictureContentHidden(content: self, isHidden: false)
self.node.alpha = 0.02
}
guard let overlayController = self.overlayController else {
return
}
overlayController.removePictureInPictureContent(content: self)
self.node.canAttachContent = false
if self.didExpand {
return
}
self.node.continuePlayingWithoutSound()
}
}
})
let _ = videoNode.enterNativePictureInPicture()
}
if let hiddenMedia = hiddenMedia {
self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(Signal<(MessageId, Media)?, NoError>.single(hiddenMedia)
|> map { messageIdAndMedia in
if let (messageId, media) = messageIdAndMedia {
return .chat(accountId, messageId, media)
} else {
return nil
}
})
}
if let (messageId, _) = hiddenMedia {
self.messageRemovedDisposable = (context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|> map { message -> Bool in
if let _ = message {
return false
} else {
return true
}
}
|> filter { $0 }
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] _ in
guard let strongSelf = self else {
return
}
overlayController.removePictureInPictureContent(content: strongSelf)
strongSelf.node.canAttachContent = false
})
}
}
deinit {
self.messageRemovedDisposable?.dispose()
self.isNativePictureInPictureActiveDisposable?.dispose()
self.pictureInPictureTimer?.invalidate()
self.node.setCanPlaybackWithoutHierarchy(false)
if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex, let mediaManager = self.mediaManager {
mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex)
}
}
func invalidatePlaybackState() {
self.pictureInPictureController?.invalidatePlaybackState()
}
var videoNode: ASDisplayNode {
return self.node
}
public func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
Queue.mainQueue().after(0.1, { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.willBegin(strongSelf)
if let overlayController = strongSelf.overlayController {
overlayController.setPictureInPictureContentHidden(content: strongSelf, isHidden: true)
}
})
}
public func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
self.didEnd(self)
}
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
print(error)
}
public func pictureInPictureControllerWillStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
}
public func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
guard let overlayController = self.overlayController else {
return
}
overlayController.removePictureInPictureContent(content: self)
self.node.canAttachContent = false
if self.didExpand {
return
}
self.node.continuePlayingWithoutSound()
}
public func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
self.expand { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.didExpand = true
if let overlayController = strongSelf.overlayController {
overlayController.setPictureInPictureContentHidden(content: strongSelf, isHidden: false)
strongSelf.node.alpha = 0.02
}
completionHandler(true)
}
}
}
@available(iOS 15.0, *)
private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPictureControllerDelegate {
private final class PlaybackDelegate: NSObject, AVPictureInPictureSampleBufferPlaybackDelegate {
@ -1079,7 +776,7 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict
guard let status = self.status else {
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)))
}
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration - status.timestamp, preferredTimescale: CMTimeScale(30.0)))
return CMTimeRange(start: CMTime(seconds: 0.0, preferredTimescale: CMTimeScale(30.0)), duration: CMTime(seconds: status.duration, preferredTimescale: CMTimeScale(30.0)))
}
public func pictureInPictureControllerIsPlaybackPaused(_ pictureInPictureController: AVPictureInPictureController) -> Bool {
@ -1230,13 +927,18 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict
}
func invalidatePlaybackState() {
self.pictureInPictureController?.invalidatePlaybackState()
guard let pictureInPictureController = self.pictureInPictureController else {
return
}
if pictureInPictureController.isPictureInPictureActive {
pictureInPictureController.invalidatePlaybackState()
}
}
public func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
self.node.setCanPlaybackWithoutHierarchy(true)
if let hiddenMedia = self.hiddenMedia, let mediaManager = self.mediaManager {
if let hiddenMedia = self.hiddenMedia, let mediaManager = self.mediaManager, !"".isEmpty {
let accountId = self.accountId
self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(Signal<(MessageId, Media)?, NoError>.single(hiddenMedia)
|> map { messageIdAndMedia in
@ -1282,6 +984,14 @@ private final class NativePictureInPictureContentImpl: NSObject, AVPictureInPict
completionHandler(true)
}
}
public func requestExpand() {
self.pictureInPictureController?.stopPictureInPicture()
}
public func stop() {
self.pictureInPictureController?.stopPictureInPicture()
}
}
final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
@ -1331,7 +1041,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private var requiresDownload = false
private var item: UniversalVideoGalleryItem?
private(set) var item: UniversalVideoGalleryItem?
private var playbackRate: Double?
private var videoQuality: UniversalVideoContentVideoQuality = .auto
private let playbackRatePromise = ValuePromise<Double>()
@ -2180,8 +1890,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let strongSelf = self, !isAnimated {
if #available(iOS 15.0, *) {
if let pictureInPictureContent = strongSelf.pictureInPictureContent as? PictureInPictureContentImpl {
pictureInPictureContent.invalidatePlaybackState()
if let nativePictureInPictureContent = strongSelf.nativePictureInPictureContent as? NativePictureInPictureContentImpl {
nativePictureInPictureContent.invalidatePlaybackState()
}
}
@ -2358,6 +2068,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if hadPreviousValue {
videoNode.canAttachContent = isVisible
if isVisible {
if let currentPictureInPictureNode = self.context.sharedContext.mediaManager.currentPictureInPictureNode as? UniversalVideoGalleryItemNode, let currentItem = currentPictureInPictureNode.item, case let .message(currentMessage, _) = currentItem.contentInfo, case let .message(message, _) = item.contentInfo, currentMessage.id == message.id {
self.skipInitialPause = true
}
if self.skipInitialPause {
self.skipInitialPause = false
} else {
@ -2397,7 +2111,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
override func activateAsInitial() {
if let videoNode = self.videoNode, self.isCentral == true {
if let videoNode = self.videoNode, self.isCentral == true, !self.initiallyActivated {
self.initiallyActivated = true
var isAnimated = false
@ -3117,7 +2831,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
if customUnembedWhenPortrait(overlayNode) {
self.beginCustomDismiss(false)
self.beginCustomDismiss(.default)
self.statusNode.isHidden = true
self.animateOut(toOverlay: overlayNode, completion: { [weak self] in
self?.completeCustomDismiss(false)
@ -3181,9 +2895,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
guard let self, let controller = self.galleryController(), let navigationController = self.baseNavigationController() else {
return
}
self.activePictureInPictureNavigationController = navigationController
self.activePictureInPictureController = controller
self.context.sharedContext.mediaManager.currentPictureInPictureNode = self
self.beginCustomDismiss(.pip)
controller.view.alpha = 0.0
controller.view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
self?.completeCustomDismiss(true)
@ -3201,6 +2918,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
guard let self else {
return
}
if self.context.sharedContext.mediaManager.currentPictureInPictureNode === self {
self.context.sharedContext.mediaManager.currentPictureInPictureNode = nil
}
if let videoNode = self.videoNode {
videoNode.setNativePictureInPictureIsActive(false)
}
@ -3227,6 +2949,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
activePictureInPictureNavigationController.currentWindow?.present(activePictureInPictureController, on: .root, blockInteraction: false, completion: {
})
activePictureInPictureController.presentationArguments = previousPresentationArguments
self.updateControlsVisibility(false)
activePictureInPictureController.view.alpha = 1.0
activePictureInPictureController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.35, completion: { _ in
@ -3240,6 +2963,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
@objc func pictureInPictureButtonPressed() {
if let currentPictureInPictureNode = self.context.sharedContext.mediaManager.currentPictureInPictureNode as? UniversalVideoGalleryItemNode, let currentItem = currentPictureInPictureNode.item, case let .message(currentMessage, _) = currentItem.contentInfo, case let .message(message, _) = self.item?.contentInfo, currentMessage.id == message.id {
if let controller = self.galleryController() as? GalleryController {
controller.dismiss(forceAway: true)
}
return
}
if #available(iOS 15.0, *) {
if let nativePictureInPictureContent = self.nativePictureInPictureContent as? NativePictureInPictureContentImpl {
addAppLogEvent(postbox: self.context.account.postbox, type: "pip_btn", peerId: self.context.account.peerId)
@ -3247,197 +2977,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
return
}
}
var isNativePictureInPictureSupported = false
switch self.item?.contentInfo {
case let .message(message, _):
for media in message.media {
if let media = media as? TelegramMediaFile, media.isVideo {
if message.id.namespace == Namespaces.Message.Cloud {
isNativePictureInPictureSupported = true
}
}
}
default:
break
}
if let item = self.item, let videoNode = self.videoNode, let overlayController = self.context.sharedContext.mediaManager.overlayMediaManager.controller {
videoNode.setContinuePlayingWithoutSoundOnLostAudioSession(false)
let context = self.context
let baseNavigationController = self.baseNavigationController()
let playbackRate = self.playbackRate
if #available(iOSApplicationExtension 15.0, iOS 15.0, *), AVPictureInPictureController.isPictureInPictureSupported(), isNativePictureInPictureSupported {
self.disablePictureInPicturePlaceholder = true
let overlayVideoNode = UniversalVideoNode(context: self.context, postbox: self.context.account.postbox, audioSession: self.context.sharedContext.mediaManager.audioSession, manager: self.context.sharedContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .overlay)
let absoluteRect = videoNode.view.convert(videoNode.view.bounds, to: nil)
overlayVideoNode.frame = absoluteRect
overlayVideoNode.updateLayout(size: absoluteRect.size, transition: .immediate)
overlayVideoNode.canAttachContent = true
var hiddenMedia: (MessageId, Media)? = nil
switch item.contentInfo {
case let .message(message, _):
for media in message.media {
if let media = media as? TelegramMediaImage {
hiddenMedia = (message.id, media)
} else if let media = media as? TelegramMediaFile, media.isVideo {
hiddenMedia = (message.id, media)
}
}
default:
break
}
let content = PictureInPictureContentImpl(context: self.context, overlayController: overlayController, mediaManager: self.context.sharedContext.mediaManager, accountId: self.context.account.id, hiddenMedia: hiddenMedia, videoNode: overlayVideoNode, canSkip: true, willBegin: { [weak self] content in
guard let strongSelf = self else {
return
}
strongSelf.beginCustomDismiss(true)
}, didEnd: { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.completeCustomDismiss(false)
}, expand: { [weak baseNavigationController] completion in
guard let contentInfo = item.contentInfo else {
return
}
switch contentInfo {
case let .message(message, _):
let gallery = GalleryController(context: context, source: .peerMessagesAtId(messageId: message.id, chatLocation: .peer(id: message.id.peerId), customTag: nil, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil)), playbackRate: playbackRate, replaceRootController: { [weak baseNavigationController] controller, ready in
if let baseNavigationController = baseNavigationController {
baseNavigationController.replaceTopController(controller, animated: false, ready: ready)
}
}, baseNavigationController: baseNavigationController)
gallery.temporaryDoNotWaitForReady = true
gallery.useSimpleAnimation = true
baseNavigationController?.view.endEditing(true)
(baseNavigationController?.topViewController as? ViewController)?.present(gallery, in: .window(.root), with: GalleryControllerPresentationArguments(transitionArguments: { id, media in
return nil
}))
gallery.onDidAppear = {
completion()
}
case .webPage:
break
}
})
self.pictureInPictureContent = content
self.context.sharedContext.mediaManager.overlayMediaManager.controller?.setPictureInPictureContent(content: content, absoluteRect: absoluteRect)
} else {
let context = self.context
let baseNavigationController = self.baseNavigationController()
let mediaManager = self.context.sharedContext.mediaManager
var expandImpl: (() -> Void)?
let shouldBeDismissed: Signal<Bool, NoError>
if let contentInfo = item.contentInfo, case let .message(message, _) = contentInfo {
shouldBeDismissed = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.Message(id: message.id))
|> map { message -> Bool in
if let _ = message {
return false
} else {
return true
}
}
|> distinctUntilChanged
} else {
shouldBeDismissed = .single(false)
}
let overlayNode = OverlayUniversalVideoNode(context: self.context, postbox: self.context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, content: item.content, shouldBeDismissed: shouldBeDismissed, expand: {
expandImpl?()
}, close: { [weak mediaManager] in
mediaManager?.setOverlayVideoNode(nil)
})
let playbackRate = self.playbackRate
expandImpl = { [weak overlayNode] in
guard let contentInfo = item.contentInfo, let overlayNode = overlayNode else {
return
}
switch contentInfo {
case let .message(message, messageIndex):
let source: GalleryControllerItemSource
if let _ = message.paidContent {
source = .standaloneMessage(message, messageIndex)
} else {
source = .peerMessagesAtId(messageId: message.id, chatLocation: .peer(id: message.id.peerId), customTag: nil, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil))
}
let gallery = GalleryController(context: context, source: source, playbackRate: playbackRate, replaceRootController: { controller, ready in
if let baseNavigationController = baseNavigationController {
baseNavigationController.replaceTopController(controller, animated: false, ready: ready)
}
}, baseNavigationController: baseNavigationController)
gallery.temporaryDoNotWaitForReady = true
baseNavigationController?.view.endEditing(true)
(baseNavigationController?.topViewController as? ViewController)?.present(gallery, in: .window(.root), with: GalleryControllerPresentationArguments(transitionArguments: { [weak overlayNode] id, media in
if let overlayNode = overlayNode, let overlaySupernode = overlayNode.supernode {
return GalleryTransitionArguments(transitionNode: (overlayNode, overlayNode.bounds, { [weak overlayNode] in
return (overlayNode?.view.snapshotContentTree(), nil)
}), addToTransitionSurface: { [weak context, weak overlaySupernode, weak overlayNode] view in
guard let context = context, let overlayNode = overlayNode else {
return
}
if context.sharedContext.mediaManager.hasOverlayVideoNode(overlayNode) {
overlaySupernode?.view.addSubview(view)
}
overlayNode.canAttachContent = false
})
} else if let info = context.sharedContext.mediaManager.galleryHiddenMediaManager.findTarget(messageId: id, media: media) {
return GalleryTransitionArguments(transitionNode: (info.1, info.1.bounds, {
return info.2()
}), addToTransitionSurface: info.0)
}
return nil
}))
case let .webPage(_, _, expandFromPip):
if let expandFromPip = expandFromPip, let baseNavigationController = baseNavigationController {
expandFromPip({ [weak overlayNode] in
if let overlayNode = overlayNode, let overlaySupernode = overlayNode.supernode {
return GalleryTransitionArguments(transitionNode: (overlayNode, overlayNode.bounds, { [weak overlayNode] in
return (overlayNode?.view.snapshotContentTree(), nil)
}), addToTransitionSurface: { [weak context, weak overlaySupernode, weak overlayNode] view in
guard let context = context, let overlayNode = overlayNode else {
return
}
if context.sharedContext.mediaManager.hasOverlayVideoNode(overlayNode) {
overlaySupernode?.view.addSubview(view)
}
overlayNode.canAttachContent = false
})
}
return nil
}, baseNavigationController, { [weak baseNavigationController] c, a in
(baseNavigationController?.topViewController as? ViewController)?.present(c, in: .window(.root), with: a)
})
}
}
}
context.sharedContext.mediaManager.setOverlayVideoNode(overlayNode)
if overlayNode.supernode != nil {
self.beginCustomDismiss(false)
self.statusNode.isHidden = true
self.animateOut(toOverlay: overlayNode, completion: { [weak self] in
self?.completeCustomDismiss(false)
})
}
}
func expandPIP() {
if #available(iOS 15.0, *) {
if let nativePictureInPictureContent = self.nativePictureInPictureContent as? NativePictureInPictureContentImpl {
nativePictureInPictureContent.requestExpand()
}
}
}
@ -3997,7 +3542,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
return
}
if let navigationController = strongSelf.baseNavigationController() {
strongSelf.beginCustomDismiss(true)
strongSelf.beginCustomDismiss(.simpleAnimation)
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: .message(id: .id(message.id), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false)))
@ -4050,7 +3595,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let peer, let (message, _, _) = strongSelf.contentInfo(), canSendMessagesToPeer(peer._asPeer()) {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuReply, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Reply"), color: theme.contextMenu.primaryColor)}, action: { [weak self] _, f in
if let self, let navigationController = self.baseNavigationController() {
self.beginCustomDismiss(true)
self.beginCustomDismiss(.simpleAnimation)
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: .message(id: .id(message.id), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: true)))

View File

@ -429,10 +429,6 @@ public final class FFMpegFileReader {
if let stream = self.stream, Int(packet.streamIndex) == stream.info.index {
let packetPts = packet.pts
/*if let focusedPart = self.focusedPart, packetPts >= focusedPart.endPts.value {
self.hasReadToEnd = true
}*/
let pts = CMTimeMake(value: packetPts, timescale: stream.info.timeScale)
let dts = CMTimeMake(value: packet.dts, timescale: stream.info.timeScale)
@ -442,7 +438,7 @@ public final class FFMpegFileReader {
if frameDuration != 0 {
duration = CMTimeMake(value: frameDuration * stream.info.timeBase, timescale: stream.info.timeScale)
} else {
duration = stream.info.fps
duration = CMTimeConvertScale(CMTimeMakeWithSeconds(1.0 / stream.info.fps.seconds, preferredTimescale: stream.info.timeScale), timescale: stream.info.timeScale, method: .quickTime)
}
let frame = MediaTrackDecodableFrame(type: .video, packet: packet, pts: pts, dts: dts, duration: duration)

View File

@ -451,29 +451,48 @@ private func chatMessageImageFileThumbnailDatas(account: Account, userLocation:
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, previewSourceFileReference: FileMediaReference?, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
let fullSizeResource = fileReference.media.resource
var reducedSizeResource: MediaResource?
if let previewSourceFileReference, let videoThumbnail = previewSourceFileReference.media.videoThumbnails.first {
reducedSizeResource = videoThumbnail.resource
} else if let videoThumbnail = fileReference.media.videoThumbnails.first {
if let videoThumbnail = fileReference.media.videoThumbnails.first {
reducedSizeResource = videoThumbnail.resource
}
var previewSourceFullSizeResource: MediaResource?
if let previewSourceFileReference {
previewSourceFullSizeResource = previewSourceFileReference.media.resource
}
var thumbnailRepresentation: TelegramMediaImageRepresentation?
if let previewSourceFileReference {
thumbnailRepresentation = useLargeThumbnail ? largestImageRepresentation(previewSourceFileReference.media.previewRepresentations) : smallestImageRepresentation(previewSourceFileReference.media.previewRepresentations)
}
if thumbnailRepresentation == nil {
thumbnailRepresentation = useLargeThumbnail ? largestImageRepresentation(fileReference.media.previewRepresentations) : smallestImageRepresentation(fileReference.media.previewRepresentations)
}
let thumbnailResource = thumbnailRepresentation?.resource
let maybePreviewSourceFullSize: Signal<MediaResourceData, NoError>
if let previewSourceFullSizeResource {
maybePreviewSourceFullSize = postbox.mediaBox.cachedResourceRepresentation(previewSourceFullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false, attemptSynchronously: synchronousLoad)
} else {
maybePreviewSourceFullSize = .single(MediaResourceData(path: "", offset: 0, size: 0, complete: false))
}
let maybeFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: false, attemptSynchronously: synchronousLoad)
let fetchedFullSize = postbox.mediaBox.cachedResourceRepresentation(fullSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true, attemptSynchronously: synchronousLoad)
var fetchedReducedSize: Signal<MediaResourceData, NoError> = .single(MediaResourceData(path: "", offset: 0, size: 0, complete: false))
if let reducedSizeResource = reducedSizeResource {
fetchedReducedSize = postbox.mediaBox.cachedResourceRepresentation(reducedSizeResource, representation: thumbnailSize ? CachedScaledVideoFirstFrameRepresentation(size: CGSize(width: 160.0, height: 160.0)) : CachedVideoFirstFrameRepresentation(), complete: false, fetch: true, attemptSynchronously: synchronousLoad)
}
let signal = maybeFullSize
let signal = combineLatest(
maybePreviewSourceFullSize,
maybeFullSize
)
|> map { maybePreviewSourceFullSize, maybeFullSize -> MediaResourceData in
if maybePreviewSourceFullSize.complete {
return maybePreviewSourceFullSize
} else {
return maybeFullSize
}
}
|> take(1)
|> mapToSignal { maybeData -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> in
if maybeData.complete && !forceThumbnail {

View File

@ -1,6 +1,6 @@
import Foundation
public struct MediaId: Hashable, PostboxCoding, CustomStringConvertible, Codable {
public struct MediaId: Hashable, Comparable, PostboxCoding, CustomStringConvertible, Codable {
public typealias Namespace = Int32
public typealias Id = Int64
@ -39,6 +39,14 @@ public struct MediaId: Hashable, PostboxCoding, CustomStringConvertible, Codable
encoder.encodeInt64(self.id, forKey: "i")
}
public static func <(lhs: MediaId, rhs: MediaId) -> Bool {
if lhs.namespace != rhs.namespace {
return lhs.namespace < rhs.namespace
} else {
return lhs.id < rhs.id
}
}
public func encodeToBuffer(_ buffer: WriteBuffer) {
var namespace = self.namespace
var id = self.id

View File

@ -0,0 +1,16 @@
include "InstantPageBlock.fbs";
include "MediaId.fbs";
include "Media.fbs";
namespace TelegramCore;
table InstantPage {
blocks:[InstantPageBlock] (id: 0, required);
media:[Media] (id: 1, required);
isComplete:bool (id: 2);
rtl:bool (id: 3);
url:string (id: 4, required);
views:int32 (id: 5);
}
root_type InstantPage;

View File

@ -0,0 +1,235 @@
include "RichText.fbs";
include "MediaId.fbs";
include "TelegramChannel.fbs";
include "PixelDimensions.fbs";
include "RichText.fbs";
namespace TelegramCore;
union InstantPageBlock_Value {
InstantPageBlock_Unsupported,
InstantPageBlock_Title,
InstantPageBlock_Subtitle,
InstantPageBlock_AuthorDate,
InstantPageBlock_Header,
InstantPageBlock_Subheader,
InstantPageBlock_Paragraph,
InstantPageBlock_Preformatted,
InstantPageBlock_Footer,
InstantPageBlock_Divider,
InstantPageBlock_Anchor,
InstantPageBlock_List,
InstantPageBlock_BlockQuote,
InstantPageBlock_PullQuote,
InstantPageBlock_Image,
InstantPageBlock_Video,
InstantPageBlock_Audio,
InstantPageBlock_Cover,
InstantPageBlock_WebEmbed,
InstantPageBlock_PostEmbed,
InstantPageBlock_Collage,
InstantPageBlock_Slideshow,
InstantPageBlock_ChannelBanner,
InstantPageBlock_Kicker,
InstantPageBlock_Table,
InstantPageBlock_Details,
InstantPageBlock_RelatedArticles,
InstantPageBlock_Map
}
table InstantPageBlock {
value:InstantPageBlock_Value (id: 1, required);
}
table InstantPageBlock_Unsupported {}
table InstantPageBlock_Title {
text:RichText (id: 0, required);
}
table InstantPageBlock_Subtitle {
text:RichText (id: 0, required);
}
table InstantPageBlock_AuthorDate {
author:RichText (id: 0, required);
date:int32 (id: 1);
}
table InstantPageBlock_Header {
text:RichText (id: 0, required);
}
table InstantPageBlock_Subheader {
text:RichText (id: 0, required);
}
table InstantPageBlock_Paragraph {
text:RichText (id: 0, required);
}
table InstantPageBlock_Preformatted {
text:RichText (id: 0, required);
}
table InstantPageBlock_Footer {
text:RichText (id: 0, required);
}
table InstantPageBlock_Divider {}
table InstantPageBlock_Anchor {
name:string (id: 0, required);
}
table InstantPageBlock_List {
items:[InstantPageListItem] (id: 0, required);
ordered:bool (id: 1);
}
table InstantPageBlock_BlockQuote {
text:RichText (id: 0, required);
caption:RichText (id: 1, required);
}
table InstantPageBlock_PullQuote {
text:RichText (id: 0, required);
caption:RichText (id: 1, required);
}
table InstantPageBlock_Image {
id:MediaId (id: 0, required);
caption:InstantPageCaption (id: 1, required);
url:string (id: 2);
webpageId:MediaId (id: 3);
}
table InstantPageBlock_Video {
id:MediaId (id: 0, required);
caption:InstantPageCaption (id: 1, required);
autoplay:bool (id: 2);
loop:bool (id: 3);
}
table InstantPageBlock_Audio {
id:MediaId (id: 0, required);
caption:InstantPageCaption (id: 1, required);
}
table InstantPageBlock_Cover {
block:InstantPageBlock (id: 0, required);
}
table InstantPageBlock_WebEmbed {
url:string (id: 0);
html:string (id: 1);
dimensions:PixelDimensions (id: 2);
caption:InstantPageCaption (id: 3, required);
stretchToWidth:bool (id: 4);
allowScrolling:bool (id: 5);
coverId:MediaId (id: 6);
}
table InstantPageBlock_PostEmbed {
url:string (id: 0, required);
webpageId:MediaId (id: 1);
avatarId:MediaId (id: 2);
author:string (id: 3, required);
date:int32 (id: 4);
blocks:[InstantPageBlock] (id: 5, required);
caption:InstantPageCaption (id: 6, required);
}
table InstantPageBlock_Collage {
items:[InstantPageBlock] (id: 0, required);
caption:InstantPageCaption (id: 1, required);
}
table InstantPageBlock_Slideshow {
items:[InstantPageBlock] (id: 0, required);
caption:InstantPageCaption (id: 1, required);
}
table InstantPageBlock_ChannelBanner {
channel:TelegramChannel (id: 0);
}
table InstantPageBlock_Kicker {
text:RichText (id: 0, required);
}
table InstantPageBlock_Table {
title:RichText (id: 0, required);
rows:[InstantPageTableRow] (id: 1, required);
bordered:bool (id: 2);
striped:bool (id: 3);
}
table InstantPageBlock_Details {
title:RichText (id: 0, required);
blocks:[InstantPageBlock] (id: 1, required);
expanded:bool (id: 2);
}
table InstantPageBlock_RelatedArticles {
title:RichText (id: 0, required);
articles:[InstantPageRelatedArticle] (id: 1, required);
}
table InstantPageBlock_Map {
latitude:float64 (id: 0);
longitude:float64 (id: 1);
zoom:int32 (id: 2);
dimensions:PixelDimensions (id: 3, required);
caption:InstantPageCaption (id: 4, required);
}
table InstantPageCaption {
text:RichText (id: 0, required);
credit:RichText (id: 1, required);
}
union InstantPageListItem_Value {
InstantPageListItem_Text,
InstantPageListItem_Blocks,
InstantPageListItem_Unknown
}
table InstantPageListItem {
value:InstantPageListItem_Value (id: 1, required);
}
table InstantPageListItem_Text {
text:RichText (id: 0, required);
number:string (id: 1);
}
table InstantPageListItem_Blocks {
blocks:[InstantPageBlock] (id: 0, required);
number:string (id: 1);
}
table InstantPageListItem_Unknown {}
table InstantPageTableCell {
text:RichText (id: 0);
header:bool (id: 1);
alignment:int32 (id: 2);
verticalAlignment:int32 (id: 3);
colspan:int32 (id: 4);
rowspan:int32 (id: 5);
}
table InstantPageTableRow {
cells:[InstantPageTableCell] (id: 0, required);
}
table InstantPageRelatedArticle {
url:string (id: 0, required);
webpageId:MediaId (id: 1, required);
title:string (id: 2);
description:string (id: 3);
photoId:MediaId (id: 4);
author:string (id: 5);
date:int32 (id: 6);
}

View File

@ -0,0 +1,23 @@
include "MediaId.fbs";
include "TelegramMediaFile.fbs";
include "TelegramMediaImage.fbs";
namespace TelegramCore;
union Media_Value {
Media_TelegramMediaFile,
Media_TelegramMediaImage
}
table Media {
value:Media_Value (id: 1, required);
}
table Media_TelegramMediaFile {
file:TelegramMediaFile (id: 0, required);
}
table Media_TelegramMediaImage {
image:TelegramMediaImage (id: 0, required);
}
root_type Media;

View File

@ -0,0 +1,5 @@
namespace TelegramCore;
struct OptionalBool {
value:bool (id: 0);
}

View File

@ -0,0 +1,11 @@
namespace TelegramCore;
table RestrictionRule {
platform:string (id: 0, required);
reason:string (id: 1, required);
text:string (id: 2, required);
}
table PeerAccessRestrictionInfo {
rules:[RestrictionRule] (id: 0, required);
}

View File

@ -0,0 +1,31 @@
namespace TelegramCore;
table PeerEmojiStatusContentEmoji {
fileId:int64 (id: 0);
}
table PeerEmojiStatusContentStarGift {
id:int64 (id: 0);
fileId:int64 (id: 1);
title:string (id: 2, required);
slug:string (id: 3, required);
patternFileId:int64 (id: 4);
innerColor:int32 (id: 5);
outerColor:int32 (id: 6);
patternColor:int32 (id: 7);
textColor:int32 (id: 8);
}
union PeerEmojiStatusContent_Value {
PeerEmojiStatusContentEmoji,
PeerEmojiStatusContentStarGift
}
table PeerEmojiStatusContent {
value:PeerEmojiStatusContent_Value (id: 1, required);
}
table PeerEmojiStatus {
content:PeerEmojiStatusContent (id: 0, required);
expirationDate:int32 (id: 1);
}

View File

@ -0,0 +1,7 @@
namespace TelegramCore;
table PeerNameColor {
value:int32 (id: 0);
}
root_type PeerNameColor;

View File

@ -0,0 +1,95 @@
include "MediaId.fbs";
include "PixelDimensions.fbs";
namespace TelegramCore;
union RichText_Value {
RichText_Empty,
RichText_Plain,
RichText_Bold,
RichText_Italic,
RichText_Underline,
RichText_Strikethrough,
RichText_Fixed,
RichText_Url,
RichText_Email,
RichText_Concat,
RichText_Subscript,
RichText_Superscript,
RichText_Marked,
RichText_Phone,
RichText_Image,
RichText_Anchor
}
table RichText {
value:RichText_Value (id: 1, required);
}
table RichText_Empty {}
table RichText_Plain {
text:string (id: 0, required);
}
table RichText_Bold {
text:RichText (id: 0, required);
}
table RichText_Italic {
text:RichText (id: 0, required);
}
table RichText_Underline {
text:RichText (id: 0, required);
}
table RichText_Strikethrough {
text:RichText (id: 0, required);
}
table RichText_Fixed {
text:RichText (id: 0, required);
}
table RichText_Url {
text:RichText (id: 0, required);
url:string (id: 1, required);
webpageId:MediaId (id: 2);
}
table RichText_Email {
text:RichText (id: 0, required);
email:string (id: 1, required);
}
table RichText_Concat {
texts:[RichText] (id: 0, required);
}
table RichText_Subscript {
text:RichText (id: 0, required);
}
table RichText_Superscript {
text:RichText (id: 0, required);
}
table RichText_Marked {
text:RichText (id: 0, required);
}
table RichText_Phone {
text:RichText (id: 0, required);
phone:string (id: 1, required);
}
table RichText_Image {
id:MediaId (id: 0, required);
dimensions:PixelDimensions (id: 1, required);
}
table RichText_Anchor {
text:RichText (id: 0, required);
name:string (id: 1, required);
}

View File

@ -0,0 +1,6 @@
namespace TelegramCore;
table StarsAmount {
value:int64 (id: 0);
nanos:int32 (id: 1);
}

View File

@ -0,0 +1,60 @@
include "PeerId.fbs";
include "TelegramPeerAccessHash.fbs";
include "TelegramMediaImageRepresentation.fbs";
include "PeerAccessRestrictionInfo.fbs";
include "TelegramChatAdminRights.fbs";
include "TelegramChatBannedRights.fbs";
include "TelegramPeerUsername.fbs";
include "Optional.fbs";
include "PeerNameColor.fbs";
include "PeerEmojiStatus.fbs";
include "StarsAmount.fbs";
namespace TelegramCore;
table TelegramChannelInfo_Broadcast {
flags:int32 (id: 0);
}
table TelegramChannelInfo_Group {
flags:int32 (id: 0);
}
union TelegramChannelInfo_Value {
TelegramChannelInfo_Broadcast,
TelegramChannelInfo_Group
}
table TelegramChannelInfo {
value:TelegramChannelInfo_Value (id: 1, required);
}
table TelegramChannel {
id:PeerId (id: 0, required);
accessHash:TelegramPeerAccessHash (id: 1);
title:string (id: 2, required);
username:string (id: 3);
photo:[TelegramMediaImageRepresentation] (id: 4);
creationDate:int32 (id: 5);
version:int32 (id: 6);
participationStatus:int32 (id: 7);
info:TelegramChannelInfo (id: 8, required);
flags:int32 (id: 9);
restrictionInfo:PeerAccessRestrictionInfo (id: 10);
adminRights:TelegramChatAdminRights (id: 11);
bannedRights:TelegramChatBannedRights (id: 12);
defaultBannedRights:TelegramChatBannedRights (id: 13);
usernames:[TelegramPeerUsername] (id: 14);
storiesHidden:OptionalBool (id: 15);
nameColor:PeerNameColor (id: 16);
backgroundEmojiId:int64 (id: 17);
profileColor:PeerNameColor (id: 18);
profileBackgroundEmojiId:int64 (id: 19);
emojiStatus:PeerEmojiStatus (id: 20);
approximateBoostLevel:int32 (id: 21);
subscriptionUntilDate:int32 (id: 22);
verificationIconFileId:int64 (id: 23);
sendPaidMessageStars:StarsAmount (id: 24);
}
root_type TelegramChannel;

View File

@ -0,0 +1,7 @@
namespace TelegramCore;
table TelegramChatAdminRights {
rights:int32 (id: 0);
}
root_type TelegramChatAdminRights;

View File

@ -0,0 +1,7 @@
namespace TelegramCore;
table TelegramChatBannedRights {
flags:int32 (id: 0);
untilDate:int32 (id: 1);
}

View File

@ -0,0 +1,48 @@
include "PeerId.fbs";
include "TelegramMediaImageRepresentation.fbs";
include "TelegramChatAdminRights.fbs";
include "TelegramChatBannedRights.fbs";
namespace TelegramCore;
table TelegramGroupRole_Creator {
rank:string (id: 0);
}
table TelegramGroupRole_Admin {
rights:TelegramChatAdminRights (id: 0, required);
rank:string (id: 1);
}
table TelegramGroupRole_Member {}
union TelegramGroupRole_Value {
TelegramGroupRole_Creator,
TelegramGroupRole_Admin,
TelegramGroupRole_Member
}
table TelegramGroupRole {
value:TelegramGroupRole_Value (id: 1, required);
}
table TelegramGroupToChannelMigrationReference {
peerId:int64 (id: 0);
accessHash:int64 (id: 1);
}
table TelegramGroup {
id:PeerId (id: 0, required);
title:string (id: 1, required);
photo:[TelegramMediaImageRepresentation] (id: 2, required);
participantCount:int32 (id: 3);
role:TelegramGroupRole (id: 4, required);
membership:int32 (id: 5);
flags:int32 (id: 6);
defaultBannedRights:TelegramChatBannedRights (id: 7);
migrationReference:TelegramGroupToChannelMigrationReference (id: 8);
creationDate:int32 (id: 9);
version:int32 (id: 10);
}
root_type TelegramGroup;

View File

@ -0,0 +1,18 @@
namespace TelegramCore;
table TelegramPeerAccessHash_Personal {
accessHash:int64 (id: 0);
}
table TelegramPeerAccessHash_GenericPublic {
accessHash:int64 (id: 0);
}
union TelegramPeerAccessHash_Value {
TelegramPeerAccessHash_Personal,
TelegramPeerAccessHash_GenericPublic
}
table TelegramPeerAccessHash {
value:TelegramPeerAccessHash_Value (id: 1, required);
}

View File

@ -0,0 +1,8 @@
namespace TelegramCore;
table TelegramPeerUsername {
flags:int32 (id: 0);
username:string (id: 1, required);
}
root_type TelegramPeerUsername;

View File

@ -0,0 +1,40 @@
include "PeerId.fbs";
include "TelegramPeerAccessHash.fbs";
include "TelegramMediaImageRepresentation.fbs";
include "PeerAccessRestrictionInfo.fbs";
include "PeerEmojiStatus.fbs";
include "TelegramPeerUsername.fbs";
include "PeerNameColor.fbs";
include "Optional.fbs";
include "StarsAmount.fbs";
namespace TelegramCore;
table BotUserInfo {
flags:int32 (id: 0);
inlinePlaceholder:string (id: 1);
}
table TelegramUser {
id:PeerId (id: 0, required);
accessHash:TelegramPeerAccessHash (id: 1);
firstName:string (id: 2);
lastName:string (id: 3);
username:string (id: 4);
phone:string (id: 5);
photo:[TelegramMediaImageRepresentation] (id: 6, required);
botInfo:BotUserInfo (id: 7);
restrictionInfo:PeerAccessRestrictionInfo (id: 8);
flags:int32 (id: 9);
emojiStatus:PeerEmojiStatus (id: 10);
usernames:[TelegramPeerUsername] (id: 11);
storiesHidden:OptionalBool (id: 12);
nameColor:PeerNameColor (id: 13);
backgroundEmojiId:int64 (id: 14);
profileColor:PeerNameColor (id: 15);
profileBackgroundEmojiId:int64 (id: 16);
subscriberCount:int32 (id: 17);
verificationIconFileId:int64 (id: 18);
}
root_type TelegramUser;

View File

@ -1,7 +1,6 @@
import Foundation
import Postbox
public enum TelegramChannelPermission {
case sendText
case sendPhoto

View File

@ -160,7 +160,7 @@ public final class AvailableReactions: Equatable, Codable {
if let staticIconData = try container.decodeIfPresent(Data.self, forKey: .staticIconData) {
var byteBuffer = ByteBuffer(data: staticIconData)
self.staticIcon = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, staticIconData)
self.staticIcon = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, staticIconData)
} else {
let staticIconData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .staticIcon)
self.staticIcon = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: staticIconData.data))))
@ -168,7 +168,7 @@ public final class AvailableReactions: Equatable, Codable {
if let appearAnimationData = try container.decodeIfPresent(Data.self, forKey: .appearAnimationData) {
var byteBuffer = ByteBuffer(data: appearAnimationData)
self.appearAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, appearAnimationData)
self.appearAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, appearAnimationData)
} else {
let appearAnimationData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .appearAnimation)
self.appearAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: appearAnimationData.data))))
@ -176,7 +176,7 @@ public final class AvailableReactions: Equatable, Codable {
if let selectAnimationData = try container.decodeIfPresent(Data.self, forKey: .selectAnimationData) {
var byteBuffer = ByteBuffer(data: selectAnimationData)
self.selectAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, selectAnimationData)
self.selectAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, selectAnimationData)
} else {
let selectAnimationData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .selectAnimation)
self.selectAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: selectAnimationData.data))))
@ -184,7 +184,7 @@ public final class AvailableReactions: Equatable, Codable {
if let activateAnimationData = try container.decodeIfPresent(Data.self, forKey: .activateAnimationData) {
var byteBuffer = ByteBuffer(data: activateAnimationData)
self.activateAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, activateAnimationData)
self.activateAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, activateAnimationData)
} else {
let activateAnimationData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .activateAnimation)
self.activateAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: activateAnimationData.data))))
@ -192,7 +192,7 @@ public final class AvailableReactions: Equatable, Codable {
if let effectAnimationData = try container.decodeIfPresent(Data.self, forKey: .effectAnimationData) {
var byteBuffer = ByteBuffer(data: effectAnimationData)
self.effectAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectAnimationData)
self.effectAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, effectAnimationData)
} else {
let effectAnimationData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .effectAnimation)
self.effectAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: effectAnimationData.data))))
@ -200,7 +200,7 @@ public final class AvailableReactions: Equatable, Codable {
if let aroundAnimationData = try container.decodeIfPresent(Data.self, forKey: .aroundAnimationData) {
var byteBuffer = ByteBuffer(data: aroundAnimationData)
self.aroundAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, aroundAnimationData)
self.aroundAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, aroundAnimationData)
} else if let aroundAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .aroundAnimation) {
self.aroundAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: aroundAnimationData.data))))
} else {
@ -209,7 +209,7 @@ public final class AvailableReactions: Equatable, Codable {
if let centerAnimationData = try container.decodeIfPresent(Data.self, forKey: .centerAnimationData) {
var byteBuffer = ByteBuffer(data: centerAnimationData)
self.centerAnimation = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, centerAnimationData)
self.centerAnimation = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, centerAnimationData)
} else if let centerAnimationData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: .centerAnimation) {
self.centerAnimation = TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: centerAnimationData.data))))
} else {

View File

@ -2,6 +2,8 @@ import Foundation
import Postbox
import TelegramApi
import SwiftSignalKit
import FlatBuffers
import FlatSerialization
public enum CachedPeerAutoremoveTimeout: Equatable, PostboxCoding {
public struct Value: Equatable, PostboxCoding {
@ -261,6 +263,16 @@ public enum PeerNameColor: Hashable {
return value
}
}
public init(flatBuffersObject: TelegramCore_PeerNameColor) throws {
self.init(rawValue: flatBuffersObject.value)
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let start = TelegramCore_PeerNameColor.startPeerNameColor(&builder)
TelegramCore_PeerNameColor.add(value: self.rawValue, &builder)
return TelegramCore_PeerNameColor.endPeerNameColor(&builder, start: start)
}
}
public struct PeerEmojiStatus: Equatable, Codable {
@ -320,6 +332,68 @@ public struct PeerEmojiStatus: Equatable, Codable {
try container.encode(textColor, forKey: .textColor)
}
}
public init(flatBuffersObject: TelegramCore_PeerEmojiStatusContent) throws {
switch flatBuffersObject.valueType {
case .peeremojistatuscontentemoji:
guard let emoji = flatBuffersObject.value(type: TelegramCore_PeerEmojiStatusContentEmoji.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .emoji(fileId: emoji.fileId)
case .peeremojistatuscontentstargift:
guard let starGift = flatBuffersObject.value(type: TelegramCore_PeerEmojiStatusContentStarGift.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .starGift(
id: starGift.id,
fileId: starGift.fileId,
title: starGift.title,
slug: starGift.slug,
patternFileId: starGift.patternFileId,
innerColor: starGift.innerColor,
outerColor: starGift.outerColor,
patternColor: starGift.patternColor,
textColor: starGift.textColor
)
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_PeerEmojiStatusContent_Value
let valueOffset: Offset
switch self {
case let .emoji(fileId):
valueType = .peeremojistatuscontentemoji
let start = TelegramCore_PeerEmojiStatusContentEmoji.startPeerEmojiStatusContentEmoji(&builder)
TelegramCore_PeerEmojiStatusContentEmoji.add(fileId: fileId, &builder)
valueOffset = TelegramCore_PeerEmojiStatusContentEmoji.endPeerEmojiStatusContentEmoji(&builder, start: start)
case let .starGift(id, fileId, title, slug, patternFileId, innerColor, outerColor, patternColor, textColor):
valueType = .peeremojistatuscontentstargift
let titleOffset = builder.create(string: title)
let slugOffset = builder.create(string: slug)
let start = TelegramCore_PeerEmojiStatusContentStarGift.startPeerEmojiStatusContentStarGift(&builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(id: id, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(fileId: fileId, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(title: titleOffset, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(slug: slugOffset, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(patternFileId: patternFileId, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(innerColor: innerColor, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(outerColor: outerColor, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(patternColor: patternColor, &builder)
TelegramCore_PeerEmojiStatusContentStarGift.add(textColor: textColor, &builder)
valueOffset = TelegramCore_PeerEmojiStatusContentStarGift.endPeerEmojiStatusContentStarGift(&builder, start: start)
}
let start = TelegramCore_PeerEmojiStatusContent.startPeerEmojiStatusContent(&builder)
TelegramCore_PeerEmojiStatusContent.add(valueType: valueType, &builder)
TelegramCore_PeerEmojiStatusContent.add(value: valueOffset, &builder)
return TelegramCore_PeerEmojiStatusContent.endPeerEmojiStatusContent(&builder, start: start)
}
}
public var content: Content
public var expirationDate: Int32?
@ -348,6 +422,20 @@ public struct PeerEmojiStatus: Equatable, Codable {
try container.encode(self.content, forKey: .content)
try container.encodeIfPresent(self.expirationDate, forKey: .expirationDate)
}
public init(flatBuffersObject: TelegramCore_PeerEmojiStatus) throws {
self.content = try Content(flatBuffersObject: flatBuffersObject.content)
self.expirationDate = flatBuffersObject.expirationDate == Int32.min ? nil : flatBuffersObject.expirationDate
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let contentOffset = self.content.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_PeerEmojiStatus.startPeerEmojiStatus(&builder)
TelegramCore_PeerEmojiStatus.add(content: contentOffset, &builder)
TelegramCore_PeerEmojiStatus.add(expirationDate: self.expirationDate ?? Int32.min, &builder)
return TelegramCore_PeerEmojiStatus.endPeerEmojiStatus(&builder, start: start)
}
}
extension PeerEmojiStatus {

View File

@ -961,7 +961,7 @@ public final class WallpaperDataResource: TelegramMediaResource {
public func TelegramMediaResource_parse(flatBuffersData data: Data) throws -> TelegramMediaResource {
var byteBuffer = ByteBuffer(data: data)
let flatBuffersObject: TelegramCore_TelegramMediaResource = getRoot(byteBuffer: &byteBuffer)
let flatBuffersObject: TelegramCore_TelegramMediaResource = FlatBuffers_getRoot(byteBuffer: &byteBuffer)
return try TelegramMediaResource_parse(flatBuffersObject: flatBuffersObject)
}
@ -970,7 +970,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
switch flatBuffersObject.valueType {
case .telegrammediaresourceCloudfilemediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudFileMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return CloudFileMediaResource(
datacenterId: Int(value.datacenterId),
@ -982,7 +982,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceClouddocumentsizemediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudDocumentSizeMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return CloudDocumentSizeMediaResource(
datacenterId: value.datacenterId,
@ -993,7 +993,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceCloudphotosizemediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return CloudPhotoSizeMediaResource(
datacenterId: value.datacenterId,
@ -1005,7 +1005,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceCloudpeerphotosizemediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudPeerPhotoSizeMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
let sizeSpec: CloudPeerPhotoSizeSpec
switch value.sizeSpec {
@ -1023,7 +1023,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceCloudstickerpackthumbnailmediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudStickerPackThumbnailMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return CloudStickerPackThumbnailMediaResource(
datacenterId: value.datacenterId,
@ -1033,7 +1033,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceClouddocumentmediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_CloudDocumentMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return CloudDocumentMediaResource(
datacenterId: Int(value.datacenterId),
@ -1045,7 +1045,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
)
case .telegrammediaresourceLocalfilemediaresource:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaResource_LocalFileMediaResource.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
return LocalFileMediaResource(
fileId: value.fileId,
@ -1053,7 +1053,7 @@ public func TelegramMediaResource_parse(flatBuffersObject: TelegramCore_Telegram
isSecretRelated: value.isSecretRelated
)
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
@ -1094,9 +1094,10 @@ public func TelegramMediaResource_serialize(resource: TelegramMediaResource, fla
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) }
let start = TelegramCore_TelegramMediaResource_CloudPhotoSizeMediaResource.startTelegramMediaResource_CloudPhotoSizeMediaResource(&builder)
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)

View File

@ -1,4 +1,7 @@
import Foundation
import Postbox
import FlatBuffers
import FlatSerialization
private enum InstantPageBlockType: Int32 {
case unsupported = 0
@ -512,6 +515,395 @@ public indirect enum InstantPageBlock: PostboxCoding, Equatable {
}
}
}
public init(flatBuffersObject: TelegramCore_InstantPageBlock) throws {
switch flatBuffersObject.valueType {
case .instantpageblockUnsupported:
self = .unsupported
case .instantpageblockTitle:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Title.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .title(try RichText(flatBuffersObject: value.text))
case .instantpageblockSubtitle:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Subtitle.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .subtitle(try RichText(flatBuffersObject: value.text))
case .instantpageblockAuthordate:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_AuthorDate.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .authorDate(author: try RichText(flatBuffersObject: value.author), date: value.date)
case .instantpageblockHeader:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Header.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .header(try RichText(flatBuffersObject: value.text))
case .instantpageblockSubheader:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Subheader.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .subheader(try RichText(flatBuffersObject: value.text))
case .instantpageblockParagraph:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Paragraph.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .paragraph(try RichText(flatBuffersObject: value.text))
case .instantpageblockPreformatted:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Preformatted.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .preformatted(try RichText(flatBuffersObject: value.text))
case .instantpageblockFooter:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Footer.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .footer(try RichText(flatBuffersObject: value.text))
case .instantpageblockDivider:
self = .divider
case .instantpageblockAnchor:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Anchor.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .anchor(value.name)
case .instantpageblockList:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_List.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .list(items: try (0 ..< value.itemsCount).map { try InstantPageListItem(flatBuffersObject: value.items(at: $0)!) }, ordered: value.ordered)
case .instantpageblockBlockquote:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_BlockQuote.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .blockQuote(text: try RichText(flatBuffersObject: value.text), caption: try RichText(flatBuffersObject: value.caption))
case .instantpageblockPullquote:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_PullQuote.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .pullQuote(text: try RichText(flatBuffersObject: value.text), caption: try RichText(flatBuffersObject: value.caption))
case .instantpageblockImage:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Image.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .image(id: MediaId(value.id), caption: try InstantPageCaption(flatBuffersObject: value.caption), url: value.url, webpageId: value.webpageId.flatMap(MediaId.init))
case .instantpageblockVideo:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Video.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .video(id: MediaId(value.id), caption: try InstantPageCaption(flatBuffersObject: value.caption), autoplay: value.autoplay, loop: value.loop)
case .instantpageblockAudio:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Audio.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .audio(id: MediaId(value.id), caption: try InstantPageCaption(flatBuffersObject: value.caption))
case .instantpageblockCover:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Cover.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .cover(try InstantPageBlock(flatBuffersObject: value.block))
case .instantpageblockWebembed:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_WebEmbed.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .webEmbed(url: value.url, html: value.html, dimensions: value.dimensions.flatMap(PixelDimensions.init), caption: try InstantPageCaption(flatBuffersObject: value.caption), stretchToWidth: value.stretchToWidth, allowScrolling: value.allowScrolling, coverId: value.coverId.flatMap(MediaId.init))
case .instantpageblockPostembed:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_PostEmbed.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .postEmbed(url: value.url, webpageId: value.webpageId.flatMap(MediaId.init), avatarId: value.avatarId.flatMap(MediaId.init), author: value.author, date: value.date, blocks: try (0 ..< value.blocksCount).map { try InstantPageBlock(flatBuffersObject: value.blocks(at: $0)!) }, caption: try InstantPageCaption(flatBuffersObject: value.caption))
case .instantpageblockCollage:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Collage.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .collage(items: try (0 ..< value.itemsCount).map { try InstantPageBlock(flatBuffersObject: value.items(at: $0)!) }, caption: try InstantPageCaption(flatBuffersObject: value.caption))
case .instantpageblockSlideshow:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Slideshow.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .slideshow(items: try (0 ..< value.itemsCount).map { try InstantPageBlock(flatBuffersObject: value.items(at: $0)!) }, caption: try InstantPageCaption(flatBuffersObject: value.caption))
case .instantpageblockChannelbanner:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_ChannelBanner.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
let channel = try value.channel.flatMap { try TelegramChannel(flatBuffersObject: $0) }
self = .channelBanner(channel)
case .instantpageblockKicker:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Kicker.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .kicker(try RichText(flatBuffersObject: value.text))
case .instantpageblockTable:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Table.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .table(title: try RichText(flatBuffersObject: value.title), rows: try (0 ..< value.rowsCount).map { try InstantPageTableRow(flatBuffersObject: value.rows(at: $0)!) }, bordered: value.bordered, striped: value.striped)
case .instantpageblockDetails:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Details.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .details(title: try RichText(flatBuffersObject: value.title), blocks: try (0 ..< value.blocksCount).map { try InstantPageBlock(flatBuffersObject: value.blocks(at: $0)!) }, expanded: value.expanded)
case .instantpageblockRelatedarticles:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_RelatedArticles.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .relatedArticles(title: try RichText(flatBuffersObject: value.title), articles: try (0 ..< value.articlesCount).map { try InstantPageRelatedArticle(flatBuffersObject: value.articles(at: $0)!) })
case .instantpageblockMap:
guard let value = flatBuffersObject.value(type: TelegramCore_InstantPageBlock_Map.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .map(latitude: value.latitude, longitude: value.longitude, zoom: value.zoom, dimensions: PixelDimensions(value.dimensions), caption: try InstantPageCaption(flatBuffersObject: value.caption))
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_InstantPageBlock_Value
let offset: Offset
switch self {
case .unsupported:
valueType = .instantpageblockUnsupported
let start = TelegramCore_InstantPageBlock_Unsupported.startInstantPageBlock_Unsupported(&builder)
offset = TelegramCore_InstantPageBlock_Unsupported.endInstantPageBlock_Unsupported(&builder, start: start)
case let .title(text):
valueType = .instantpageblockTitle
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Title.startInstantPageBlock_Title(&builder)
TelegramCore_InstantPageBlock_Title.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Title.endInstantPageBlock_Title(&builder, start: start)
case let .subtitle(text):
valueType = .instantpageblockSubtitle
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Subtitle.startInstantPageBlock_Subtitle(&builder)
TelegramCore_InstantPageBlock_Subtitle.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Subtitle.endInstantPageBlock_Subtitle(&builder, start: start)
case let .authorDate(author, date):
valueType = .instantpageblockAuthordate
let authorOffset = author.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_AuthorDate.startInstantPageBlock_AuthorDate(&builder)
TelegramCore_InstantPageBlock_AuthorDate.add(author: authorOffset, &builder)
TelegramCore_InstantPageBlock_AuthorDate.add(date: date, &builder)
offset = TelegramCore_InstantPageBlock_AuthorDate.endInstantPageBlock_AuthorDate(&builder, start: start)
case let .header(text):
valueType = .instantpageblockHeader
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Header.startInstantPageBlock_Header(&builder)
TelegramCore_InstantPageBlock_Header.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Header.endInstantPageBlock_Header(&builder, start: start)
case let .subheader(text):
valueType = .instantpageblockSubheader
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Subheader.startInstantPageBlock_Subheader(&builder)
TelegramCore_InstantPageBlock_Subheader.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Subheader.endInstantPageBlock_Subheader(&builder, start: start)
case let .paragraph(text):
valueType = .instantpageblockParagraph
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Paragraph.startInstantPageBlock_Paragraph(&builder)
TelegramCore_InstantPageBlock_Paragraph.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Paragraph.endInstantPageBlock_Paragraph(&builder, start: start)
case let .preformatted(text):
valueType = .instantpageblockPreformatted
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Preformatted.startInstantPageBlock_Preformatted(&builder)
TelegramCore_InstantPageBlock_Preformatted.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Preformatted.endInstantPageBlock_Preformatted(&builder, start: start)
case let .footer(text):
valueType = .instantpageblockFooter
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Footer.startInstantPageBlock_Footer(&builder)
TelegramCore_InstantPageBlock_Footer.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Footer.endInstantPageBlock_Footer(&builder, start: start)
case .divider:
valueType = .instantpageblockDivider
let start = TelegramCore_InstantPageBlock_Divider.startInstantPageBlock_Divider(&builder)
offset = TelegramCore_InstantPageBlock_Divider.endInstantPageBlock_Divider(&builder, start: start)
case let .anchor(name):
valueType = .instantpageblockAnchor
let nameOffset = builder.create(string: name)
let start = TelegramCore_InstantPageBlock_Anchor.startInstantPageBlock_Anchor(&builder)
TelegramCore_InstantPageBlock_Anchor.add(name: nameOffset, &builder)
offset = TelegramCore_InstantPageBlock_Anchor.endInstantPageBlock_Anchor(&builder, start: start)
case let .list(items, ordered):
valueType = .instantpageblockList
let itemsOffsets = items.map { $0.encodeToFlatBuffers(builder: &builder) }
let itemsOffset = builder.createVector(ofOffsets: itemsOffsets, len: itemsOffsets.count)
let start = TelegramCore_InstantPageBlock_List.startInstantPageBlock_List(&builder)
TelegramCore_InstantPageBlock_List.addVectorOf(items: itemsOffset, &builder)
TelegramCore_InstantPageBlock_List.add(ordered: ordered, &builder)
offset = TelegramCore_InstantPageBlock_List.endInstantPageBlock_List(&builder, start: start)
case let .blockQuote(text, caption):
valueType = .instantpageblockBlockquote
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_BlockQuote.startInstantPageBlock_BlockQuote(&builder)
TelegramCore_InstantPageBlock_BlockQuote.add(text: textOffset, &builder)
TelegramCore_InstantPageBlock_BlockQuote.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_BlockQuote.endInstantPageBlock_BlockQuote(&builder, start: start)
case let .pullQuote(text, caption):
valueType = .instantpageblockPullquote
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_PullQuote.startInstantPageBlock_PullQuote(&builder)
TelegramCore_InstantPageBlock_PullQuote.add(text: textOffset, &builder)
TelegramCore_InstantPageBlock_PullQuote.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_PullQuote.endInstantPageBlock_PullQuote(&builder, start: start)
case let .image(id, caption, url, webpageId):
valueType = .instantpageblockImage
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let urlOffset = url.flatMap { builder.create(string: $0) }
let start = TelegramCore_InstantPageBlock_Image.startInstantPageBlock_Image(&builder)
TelegramCore_InstantPageBlock_Image.add(id: id.asFlatBuffersObject(), &builder)
TelegramCore_InstantPageBlock_Image.add(caption: captionOffset, &builder)
if let urlOffset {
TelegramCore_InstantPageBlock_Image.add(url: urlOffset, &builder)
}
if let webpageId {
TelegramCore_InstantPageBlock_Image.add(webpageId: webpageId.asFlatBuffersObject(), &builder)
}
offset = TelegramCore_InstantPageBlock_Image.endInstantPageBlock_Image(&builder, start: start)
case let .video(id, caption, autoplay, loop):
valueType = .instantpageblockVideo
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Video.startInstantPageBlock_Video(&builder)
TelegramCore_InstantPageBlock_Video.add(id: id.asFlatBuffersObject(), &builder)
TelegramCore_InstantPageBlock_Video.add(caption: captionOffset, &builder)
TelegramCore_InstantPageBlock_Video.add(autoplay: autoplay, &builder)
TelegramCore_InstantPageBlock_Video.add(loop: loop, &builder)
offset = TelegramCore_InstantPageBlock_Video.endInstantPageBlock_Video(&builder, start: start)
case let .audio(id, caption):
valueType = .instantpageblockAudio
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Audio.startInstantPageBlock_Audio(&builder)
TelegramCore_InstantPageBlock_Audio.add(id: id.asFlatBuffersObject(), &builder)
TelegramCore_InstantPageBlock_Audio.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_Audio.endInstantPageBlock_Audio(&builder, start: start)
case let .cover(block):
valueType = .instantpageblockCover
let blockOffset = block.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Cover.startInstantPageBlock_Cover(&builder)
TelegramCore_InstantPageBlock_Cover.add(block: blockOffset, &builder)
offset = TelegramCore_InstantPageBlock_Cover.endInstantPageBlock_Cover(&builder, start: start)
case let .webEmbed(url, html, dimensions, caption, stretchToWidth, allowScrolling, coverId):
valueType = .instantpageblockWebembed
let urlOffset = url.flatMap { builder.create(string: $0) }
let htmlOffset = html.flatMap { builder.create(string: $0) }
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_WebEmbed.startInstantPageBlock_WebEmbed(&builder)
if let urlOffset {
TelegramCore_InstantPageBlock_WebEmbed.add(url: urlOffset, &builder)
}
if let htmlOffset {
TelegramCore_InstantPageBlock_WebEmbed.add(html: htmlOffset, &builder)
}
if let dimensions {
TelegramCore_InstantPageBlock_WebEmbed.add(dimensions: dimensions.asFlatBuffersObject(), &builder)
}
TelegramCore_InstantPageBlock_WebEmbed.add(caption: captionOffset, &builder)
TelegramCore_InstantPageBlock_WebEmbed.add(stretchToWidth: stretchToWidth, &builder)
TelegramCore_InstantPageBlock_WebEmbed.add(allowScrolling: allowScrolling, &builder)
if let coverId {
TelegramCore_InstantPageBlock_WebEmbed.add(coverId: coverId.asFlatBuffersObject(), &builder)
}
offset = TelegramCore_InstantPageBlock_WebEmbed.endInstantPageBlock_WebEmbed(&builder, start: start)
case let .postEmbed(url, webpageId, avatarId, author, date, blocks, caption):
valueType = .instantpageblockPostembed
let urlOffset = builder.create(string: url)
let authorOffset = builder.create(string: author)
let blocksOffsets = blocks.map { $0.encodeToFlatBuffers(builder: &builder) }
let blocksOffset = builder.createVector(ofOffsets: blocksOffsets, len: blocksOffsets.count)
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_PostEmbed.startInstantPageBlock_PostEmbed(&builder)
TelegramCore_InstantPageBlock_PostEmbed.add(url: urlOffset, &builder)
if let webpageId {
TelegramCore_InstantPageBlock_PostEmbed.add(webpageId: webpageId.asFlatBuffersObject(), &builder)
}
if let avatarId {
TelegramCore_InstantPageBlock_PostEmbed.add(avatarId: avatarId.asFlatBuffersObject(), &builder)
}
TelegramCore_InstantPageBlock_PostEmbed.add(author: authorOffset, &builder)
TelegramCore_InstantPageBlock_PostEmbed.add(date: date, &builder)
TelegramCore_InstantPageBlock_PostEmbed.addVectorOf(blocks: blocksOffset, &builder)
TelegramCore_InstantPageBlock_PostEmbed.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_PostEmbed.endInstantPageBlock_PostEmbed(&builder, start: start)
case let .collage(items, caption):
valueType = .instantpageblockCollage
let itemsOffsets = items.map { $0.encodeToFlatBuffers(builder: &builder) }
let itemsOffset = builder.createVector(ofOffsets: itemsOffsets, len: itemsOffsets.count)
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Collage.startInstantPageBlock_Collage(&builder)
TelegramCore_InstantPageBlock_Collage.addVectorOf(items: itemsOffset, &builder)
TelegramCore_InstantPageBlock_Collage.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_Collage.endInstantPageBlock_Collage(&builder, start: start)
case let .slideshow(items, caption):
valueType = .instantpageblockSlideshow
let itemsOffsets = items.map { $0.encodeToFlatBuffers(builder: &builder) }
let itemsOffset = builder.createVector(ofOffsets: itemsOffsets, len: itemsOffsets.count)
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Slideshow.startInstantPageBlock_Slideshow(&builder)
TelegramCore_InstantPageBlock_Slideshow.addVectorOf(items: itemsOffset, &builder)
TelegramCore_InstantPageBlock_Slideshow.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_Slideshow.endInstantPageBlock_Slideshow(&builder, start: start)
case let .channelBanner(channel):
valueType = .instantpageblockChannelbanner
let channelOffset = channel.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let start = TelegramCore_InstantPageBlock_ChannelBanner.startInstantPageBlock_ChannelBanner(&builder)
if let channelOffset {
TelegramCore_InstantPageBlock_ChannelBanner.add(channel: channelOffset, &builder)
}
offset = TelegramCore_InstantPageBlock_ChannelBanner.endInstantPageBlock_ChannelBanner(&builder, start: start)
case let .kicker(text):
valueType = .instantpageblockKicker
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Kicker.startInstantPageBlock_Kicker(&builder)
TelegramCore_InstantPageBlock_Kicker.add(text: textOffset, &builder)
offset = TelegramCore_InstantPageBlock_Kicker.endInstantPageBlock_Kicker(&builder, start: start)
case let .table(title, rows, bordered, striped):
valueType = .instantpageblockTable
let titleOffset = title.encodeToFlatBuffers(builder: &builder)
let rowsOffsets = rows.map { $0.encodeToFlatBuffers(builder: &builder) }
let rowsOffset = builder.createVector(ofOffsets: rowsOffsets, len: rowsOffsets.count)
let start = TelegramCore_InstantPageBlock_Table.startInstantPageBlock_Table(&builder)
TelegramCore_InstantPageBlock_Table.add(title: titleOffset, &builder)
TelegramCore_InstantPageBlock_Table.addVectorOf(rows: rowsOffset, &builder)
TelegramCore_InstantPageBlock_Table.add(bordered: bordered, &builder)
TelegramCore_InstantPageBlock_Table.add(striped: striped, &builder)
offset = TelegramCore_InstantPageBlock_Table.endInstantPageBlock_Table(&builder, start: start)
case let .details(title, blocks, expanded):
valueType = .instantpageblockDetails
let titleOffset = title.encodeToFlatBuffers(builder: &builder)
let blocksOffsets = blocks.map { $0.encodeToFlatBuffers(builder: &builder) }
let blocksOffset = builder.createVector(ofOffsets: blocksOffsets, len: blocksOffsets.count)
let start = TelegramCore_InstantPageBlock_Details.startInstantPageBlock_Details(&builder)
TelegramCore_InstantPageBlock_Details.add(title: titleOffset, &builder)
TelegramCore_InstantPageBlock_Details.addVectorOf(blocks: blocksOffset, &builder)
TelegramCore_InstantPageBlock_Details.add(expanded: expanded, &builder)
offset = TelegramCore_InstantPageBlock_Details.endInstantPageBlock_Details(&builder, start: start)
case let .relatedArticles(title, articles):
valueType = .instantpageblockRelatedarticles
let titleOffset = title.encodeToFlatBuffers(builder: &builder)
let articlesOffsets = articles.map { $0.encodeToFlatBuffers(builder: &builder) }
let articlesOffset = builder.createVector(ofOffsets: articlesOffsets, len: articlesOffsets.count)
let start = TelegramCore_InstantPageBlock_RelatedArticles.startInstantPageBlock_RelatedArticles(&builder)
TelegramCore_InstantPageBlock_RelatedArticles.add(title: titleOffset, &builder)
TelegramCore_InstantPageBlock_RelatedArticles.addVectorOf(articles: articlesOffset, &builder)
offset = TelegramCore_InstantPageBlock_RelatedArticles.endInstantPageBlock_RelatedArticles(&builder, start: start)
case let .map(latitude, longitude, zoom, dimensions, caption):
valueType = .instantpageblockMap
let captionOffset = caption.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageBlock_Map.startInstantPageBlock_Map(&builder)
TelegramCore_InstantPageBlock_Map.add(latitude: latitude, &builder)
TelegramCore_InstantPageBlock_Map.add(longitude: longitude, &builder)
TelegramCore_InstantPageBlock_Map.add(zoom: zoom, &builder)
TelegramCore_InstantPageBlock_Map.add(dimensions: dimensions.asFlatBuffersObject(), &builder)
TelegramCore_InstantPageBlock_Map.add(caption: captionOffset, &builder)
offset = TelegramCore_InstantPageBlock_Map.endInstantPageBlock_Map(&builder, start: start)
}
return TelegramCore_InstantPageBlock.createInstantPageBlock(&builder, valueType: valueType, valueOffset: offset)
}
}
public final class InstantPageCaption: PostboxCoding, Equatable {
@ -542,6 +934,21 @@ public final class InstantPageCaption: PostboxCoding, Equatable {
}
return true
}
public init(flatBuffersObject: TelegramCore_InstantPageCaption) throws {
self.text = try RichText(flatBuffersObject: flatBuffersObject.text)
self.credit = try RichText(flatBuffersObject: flatBuffersObject.credit)
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let textOffset = self.text.encodeToFlatBuffers(builder: &builder)
let creditOffset = self.credit.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_InstantPageCaption.startInstantPageCaption(&builder)
TelegramCore_InstantPageCaption.add(text: textOffset, &builder)
TelegramCore_InstantPageCaption.add(credit: creditOffset, &builder)
let offset = TelegramCore_InstantPageCaption.endInstantPageCaption(&builder, start: start)
return offset
}
}
private enum InstantPageListItemType: Int32 {
@ -611,6 +1018,69 @@ public indirect enum InstantPageListItem: PostboxCoding, Equatable {
}
}
}
public init(flatBuffersObject: TelegramCore_InstantPageListItem) throws {
switch flatBuffersObject.valueType {
case .instantpagelistitemText:
guard let textValue = flatBuffersObject.value(type: TelegramCore_InstantPageListItem_Text.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .text(try RichText(flatBuffersObject: textValue.text), textValue.number)
case .instantpagelistitemBlocks:
guard let blocksValue = flatBuffersObject.value(type: TelegramCore_InstantPageListItem_Blocks.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
let blocks = try (0 ..< blocksValue.blocksCount).map { i in
return try InstantPageBlock(flatBuffersObject: blocksValue.blocks(at: i)!)
}
self = .blocks(blocks, blocksValue.number)
case .instantpagelistitemUnknown:
self = .unknown
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_InstantPageListItem_Value
let offset: Offset
switch self {
case let .text(text, number):
valueType = .instantpagelistitemText
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let numberOffset = number.map { builder.create(string: $0) } ?? Offset()
let start = TelegramCore_InstantPageListItem_Text.startInstantPageListItem_Text(&builder)
TelegramCore_InstantPageListItem_Text.add(text: textOffset, &builder)
if let _ = number {
TelegramCore_InstantPageListItem_Text.add(number: numberOffset, &builder)
}
offset = TelegramCore_InstantPageListItem_Text.endInstantPageListItem_Text(&builder, start: start)
case let .blocks(blocks, number):
valueType = .instantpagelistitemBlocks
let blocksOffsets = blocks.map { $0.encodeToFlatBuffers(builder: &builder) }
let blocksOffset = builder.createVector(ofOffsets: blocksOffsets, len: blocksOffsets.count)
let numberOffset = number.map { builder.create(string: $0) } ?? Offset()
let start = TelegramCore_InstantPageListItem_Blocks.startInstantPageListItem_Blocks(&builder)
TelegramCore_InstantPageListItem_Blocks.addVectorOf(blocks: blocksOffset, &builder)
if let _ = number {
TelegramCore_InstantPageListItem_Blocks.add(number: numberOffset, &builder)
}
offset = TelegramCore_InstantPageListItem_Blocks.endInstantPageListItem_Blocks(&builder, start: start)
case .unknown:
valueType = .instantpagelistitemUnknown
let start = TelegramCore_InstantPageListItem_Unknown.startInstantPageListItem_Unknown(&builder)
offset = TelegramCore_InstantPageListItem_Unknown.endInstantPageListItem_Unknown(&builder, start: start)
}
let start = TelegramCore_InstantPageListItem.startInstantPageListItem(&builder)
TelegramCore_InstantPageListItem.add(valueType: valueType, &builder)
TelegramCore_InstantPageListItem.add(value: offset, &builder)
return TelegramCore_InstantPageListItem.endInstantPageListItem(&builder, start: start)
}
}
public enum TableHorizontalAlignment: Int32 {
@ -685,6 +1155,30 @@ public final class InstantPageTableCell: PostboxCoding, Equatable {
}
return true
}
public init(flatBuffersObject: TelegramCore_InstantPageTableCell) throws {
self.text = try flatBuffersObject.text.map { try RichText(flatBuffersObject: $0) }
self.header = flatBuffersObject.header
self.alignment = TableHorizontalAlignment(rawValue: flatBuffersObject.alignment) ?? .left
self.verticalAlignment = TableVerticalAlignment(rawValue: flatBuffersObject.verticalAlignment) ?? .top
self.colspan = flatBuffersObject.colspan
self.rowspan = flatBuffersObject.rowspan
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let textOffset = text.map { $0.encodeToFlatBuffers(builder: &builder) } ?? Offset()
let start = TelegramCore_InstantPageTableCell.startInstantPageTableCell(&builder)
if let _ = text {
TelegramCore_InstantPageTableCell.add(text: textOffset, &builder)
}
TelegramCore_InstantPageTableCell.add(header: header, &builder)
TelegramCore_InstantPageTableCell.add(alignment: alignment.rawValue, &builder)
TelegramCore_InstantPageTableCell.add(verticalAlignment: verticalAlignment.rawValue, &builder)
TelegramCore_InstantPageTableCell.add(colspan: colspan, &builder)
TelegramCore_InstantPageTableCell.add(rowspan: rowspan, &builder)
return TelegramCore_InstantPageTableCell.endInstantPageTableCell(&builder, start: start)
}
}
public final class InstantPageTableRow: PostboxCoding, Equatable {
@ -705,6 +1199,21 @@ public final class InstantPageTableRow: PostboxCoding, Equatable {
public static func ==(lhs: InstantPageTableRow, rhs: InstantPageTableRow) -> Bool {
return lhs.cells == rhs.cells
}
public init(flatBuffersObject: TelegramCore_InstantPageTableRow) throws {
self.cells = try (0 ..< flatBuffersObject.cellsCount).map { i in
return try InstantPageTableCell(flatBuffersObject: flatBuffersObject.cells(at: i)!)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let cellsOffsets = cells.map { $0.encodeToFlatBuffers(builder: &builder) }
let cellsOffset = builder.createVector(ofOffsets: cellsOffsets, len: cellsOffsets.count)
let start = TelegramCore_InstantPageTableRow.startInstantPageTableRow(&builder)
TelegramCore_InstantPageTableRow.addVectorOf(cells: cellsOffset, &builder)
return TelegramCore_InstantPageTableRow.endInstantPageTableRow(&builder, start: start)
}
}
public final class InstantPageRelatedArticle: PostboxCoding, Equatable {
@ -801,6 +1310,45 @@ public final class InstantPageRelatedArticle: PostboxCoding, Equatable {
}
return true
}
public init(flatBuffersObject: TelegramCore_InstantPageRelatedArticle) throws {
self.url = flatBuffersObject.url
self.webpageId = MediaId(flatBuffersObject.webpageId)
self.title = flatBuffersObject.title
self.description = flatBuffersObject.description
self.photoId = flatBuffersObject.photoId.flatMap(MediaId.init)
self.author = flatBuffersObject.author
self.date = flatBuffersObject.date == Int32.min ? nil : flatBuffersObject.date
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let urlOffset = builder.create(string: url)
let titleOffset = title.map { builder.create(string: $0) }
let descriptionOffset = description.map { builder.create(string: $0) }
let authorOffset = author.map { builder.create(string: $0) }
let start = TelegramCore_InstantPageRelatedArticle.startInstantPageRelatedArticle(&builder)
TelegramCore_InstantPageRelatedArticle.add(url: urlOffset, &builder)
TelegramCore_InstantPageRelatedArticle.add(webpageId: webpageId.asFlatBuffersObject(), &builder)
if let titleOffset {
TelegramCore_InstantPageRelatedArticle.add(title: titleOffset, &builder)
}
if let descriptionOffset {
TelegramCore_InstantPageRelatedArticle.add(description: descriptionOffset, &builder)
}
if let photoId {
TelegramCore_InstantPageRelatedArticle.add(photoId: photoId.asFlatBuffersObject(), &builder)
}
if let authorOffset {
TelegramCore_InstantPageRelatedArticle.add(author: authorOffset, &builder)
}
if let date {
TelegramCore_InstantPageRelatedArticle.add(date: date, &builder)
} else {
TelegramCore_InstantPageRelatedArticle.add(date: Int32.min, &builder)
}
return TelegramCore_InstantPageRelatedArticle.endInstantPageRelatedArticle(&builder, start: start)
}
}
private final class MediaDictionary: PostboxCoding {
@ -862,6 +1410,17 @@ public final class InstantPage: PostboxCoding, Equatable {
self.rtl = decoder.decodeInt32ForKey("r", orElse: 0) != 0
self.url = decoder.decodeStringForKey("url", orElse: "")
self.views = decoder.decodeOptionalInt32ForKey("v")
#if DEBUG
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)
let serializedData = builder.data
var byteBuffer = ByteBuffer(data: serializedData)
let deserializedValue = FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_InstantPage
let parsedValue = try! InstantPage(flatBuffersObject: deserializedValue)
assert(self == parsedValue)
#endif
}
public func encode(_ encoder: PostboxEncoder) {
@ -908,4 +1467,119 @@ public final class InstantPage: PostboxCoding, Equatable {
}
return true
}
public init(flatBuffersObject: TelegramCore_InstantPage) throws {
self.blocks = try (0 ..< flatBuffersObject.blocksCount).map { i in
return try InstantPageBlock(flatBuffersObject: flatBuffersObject.blocks(at: i)!)
}
//TODO:release support other media types
var media: [MediaId: Media] = [:]
for i in 0 ..< flatBuffersObject.mediaCount {
let mediaItem = flatBuffersObject.media(at: i)!
switch mediaItem.valueType {
case .mediaTelegrammediafile:
guard let value = mediaItem.value(type: TelegramCore_Media_TelegramMediaFile.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
let parsedMedia = try TelegramMediaFile(flatBuffersObject: value.file)
media[parsedMedia.fileId] = parsedMedia
case .mediaTelegrammediaimage:
guard let value = mediaItem.value(type: TelegramCore_Media_TelegramMediaImage.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
let parsedMedia = try TelegramMediaImage(flatBuffersObject: value.image)
media[parsedMedia.imageId] = parsedMedia
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
self.media = media
self.isComplete = flatBuffersObject.isComplete
self.rtl = flatBuffersObject.rtl
self.url = flatBuffersObject.url
self.views = flatBuffersObject.views == Int32.min ? nil : flatBuffersObject.views
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let blocksOffsets = self.blocks.map { block in
return block.encodeToFlatBuffers(builder: &builder)
}
let blocksOffset = builder.createVector(ofOffsets: blocksOffsets, len: blocksOffsets.count)
var mediaOffsets: [Offset] = []
for (_, media) in self.media.sorted(by: { $0.key < $1.key }) {
switch media {
case let file as TelegramMediaFile:
let fileOffset = file.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_Media_TelegramMediaFile.startMedia_TelegramMediaFile(&builder)
TelegramCore_Media_TelegramMediaFile.add(file: fileOffset, &builder)
let offset = TelegramCore_Media_TelegramMediaFile.endMedia_TelegramMediaFile(&builder, start: start)
mediaOffsets.append(TelegramCore_Media.createMedia(&builder, valueType: .mediaTelegrammediafile, valueOffset: offset))
case let image as TelegramMediaImage:
let imageOffset = image.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_Media_TelegramMediaImage.startMedia_TelegramMediaImage(&builder)
TelegramCore_Media_TelegramMediaImage.add(image: imageOffset, &builder)
let offset = TelegramCore_Media_TelegramMediaImage.endMedia_TelegramMediaImage(&builder, start: start)
mediaOffsets.append(TelegramCore_Media.createMedia(&builder, valueType: .mediaTelegrammediaimage, valueOffset: offset))
default:
assertionFailure()
}
}
let mediaOffset = builder.createVector(ofOffsets: mediaOffsets, len: mediaOffsets.count)
let urlOffset = builder.create(string: self.url)
let start = TelegramCore_InstantPage.startInstantPage(&builder)
TelegramCore_InstantPage.addVectorOf(blocks: blocksOffset, &builder)
TelegramCore_InstantPage.addVectorOf(media: mediaOffset, &builder)
TelegramCore_InstantPage.add(isComplete: self.isComplete, &builder)
TelegramCore_InstantPage.add(rtl: self.rtl, &builder)
TelegramCore_InstantPage.add(url: urlOffset, &builder)
TelegramCore_InstantPage.add(views: self.views ?? Int32.min, &builder)
return TelegramCore_InstantPage.endInstantPage(&builder, start: start)
}
}
public extension InstantPage {
struct Accessor: Equatable {
let _wrappedInstantPage: InstantPage?
let _wrapped: TelegramCore_InstantPage?
let _wrappedData: Data?
public init(_ wrapped: TelegramCore_InstantPage, _ _wrappedData: Data) {
self._wrapped = wrapped
self._wrappedData = _wrappedData
self._wrappedInstantPage = nil
}
public init(_ wrapped: InstantPage) {
self._wrapped = nil
self._wrappedData = nil
self._wrappedInstantPage = wrapped
}
public func _parse() -> InstantPage {
if let _wrappedInstantPage = self._wrappedInstantPage {
return _wrappedInstantPage
} else {
return try! InstantPage(flatBuffersObject: self._wrapped!)
}
}
public static func ==(lhs: InstantPage.Accessor, rhs: InstantPage.Accessor) -> Bool {
if let lhsWrappedInstantPage = lhs._wrappedInstantPage, let rhsWrappedInstantPage = rhs._wrappedInstantPage {
return lhsWrappedInstantPage === rhsWrappedInstantPage
} else if let lhsWrappedData = lhs._wrappedData, let rhsWrappedData = rhs._wrappedData {
return lhsWrappedData == rhsWrappedData
} else {
assertionFailure()
return lhs._parse() == rhs._parse()
}
}
}
}

View File

@ -79,7 +79,7 @@ public extension PartialMediaReference {
switch flatBuffersObject.valueType {
case .partialmediareferenceMessage:
guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_Message.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
if let message = value.message {
self = .message(message: try MessageReference(flatBuffersObject: message))
@ -88,7 +88,7 @@ public extension PartialMediaReference {
}
case .partialmediareferenceWebpage:
guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_WebPage.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
if let webPage = value.webPage {
self = .webPage(webPage: try WebpageReference(flatBuffersObject: webPage))
@ -97,7 +97,7 @@ public extension PartialMediaReference {
}
case .partialmediareferenceStickerpack:
guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_StickerPack.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .stickerPack(stickerPack: try StickerPackReference(flatBuffersObject: value.stickerPack))
case .partialmediareferenceSavedgif:
@ -107,7 +107,7 @@ public extension PartialMediaReference {
case .partialmediareferenceRecentsticker:
self = .recentSticker
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}

View File

@ -1,4 +1,6 @@
import Foundation
import FlatBuffers
import FlatSerialization
public enum TelegramPeerAccessHash: Hashable {
case personal(Int64)
@ -12,4 +14,44 @@ public enum TelegramPeerAccessHash: Hashable {
return genericPublic
}
}
public init(flatBuffersObject: TelegramCore_TelegramPeerAccessHash) throws {
switch flatBuffersObject.valueType {
case .telegrampeeraccesshashPersonal:
guard let personal = flatBuffersObject.value(type: TelegramCore_TelegramPeerAccessHash_Personal.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .personal(personal.accessHash)
case .telegrampeeraccesshashGenericpublic:
guard let genericPublic = flatBuffersObject.value(type: TelegramCore_TelegramPeerAccessHash_GenericPublic.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .genericPublic(genericPublic.accessHash)
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_TelegramPeerAccessHash_Value
let valueOffset: Offset
switch self {
case let .personal(accessHash):
valueType = .telegrampeeraccesshashPersonal
let start = TelegramCore_TelegramPeerAccessHash_Personal.startTelegramPeerAccessHash_Personal(&builder)
TelegramCore_TelegramPeerAccessHash_Personal.add(accessHash: accessHash, &builder)
valueOffset = TelegramCore_TelegramPeerAccessHash_Personal.endTelegramPeerAccessHash_Personal(&builder, start: start)
case let .genericPublic(accessHash):
valueType = .telegrampeeraccesshashGenericpublic
let start = TelegramCore_TelegramPeerAccessHash_GenericPublic.startTelegramPeerAccessHash_GenericPublic(&builder)
TelegramCore_TelegramPeerAccessHash_GenericPublic.add(accessHash: accessHash, &builder)
valueOffset = TelegramCore_TelegramPeerAccessHash_GenericPublic.endTelegramPeerAccessHash_GenericPublic(&builder, start: start)
}
let start = TelegramCore_TelegramPeerAccessHash.startTelegramPeerAccessHash(&builder)
TelegramCore_TelegramPeerAccessHash.add(valueType: valueType, &builder)
TelegramCore_TelegramPeerAccessHash.add(value: valueOffset, &builder)
return TelegramCore_TelegramPeerAccessHash.endTelegramPeerAccessHash(&builder, start: start)
}
}

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
public final class RestrictionRule: PostboxCoding, Equatable {
public let platform: String
@ -41,6 +43,24 @@ public final class RestrictionRule: PostboxCoding, Equatable {
}
return true
}
public init(flatBuffersObject: TelegramCore_RestrictionRule) throws {
self.platform = flatBuffersObject.platform
self.reason = flatBuffersObject.reason
self.text = flatBuffersObject.text
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let platformOffset = builder.create(string: self.platform)
let reasonOffset = builder.create(string: self.reason)
let textOffset = builder.create(string: self.text)
let start = TelegramCore_RestrictionRule.startRestrictionRule(&builder)
TelegramCore_RestrictionRule.add(platform: platformOffset, &builder)
TelegramCore_RestrictionRule.add(reason: reasonOffset, &builder)
TelegramCore_RestrictionRule.add(text: textOffset, &builder)
return TelegramCore_RestrictionRule.endRestrictionRule(&builder, start: start)
}
}
public final class PeerAccessRestrictionInfo: PostboxCoding, Equatable {
@ -65,4 +85,17 @@ public final class PeerAccessRestrictionInfo: PostboxCoding, Equatable {
public static func ==(lhs: PeerAccessRestrictionInfo, rhs: PeerAccessRestrictionInfo) -> Bool {
return lhs.rules == rhs.rules
}
public init(flatBuffersObject: TelegramCore_PeerAccessRestrictionInfo) throws {
self.rules = try (0 ..< flatBuffersObject.rulesCount).map { try RestrictionRule(flatBuffersObject: flatBuffersObject.rules(at: $0)!) }
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let rulesOffsets = self.rules.map { $0.encodeToFlatBuffers(builder: &builder) }
let rulesOffset = builder.createVector(ofOffsets: rulesOffsets, len: rulesOffsets.count)
let start = TelegramCore_PeerAccessRestrictionInfo.startPeerAccessRestrictionInfo(&builder)
TelegramCore_PeerAccessRestrictionInfo.addVectorOf(rules: rulesOffset, &builder)
return TelegramCore_PeerAccessRestrictionInfo.endPeerAccessRestrictionInfo(&builder, start: start)
}
}

View File

@ -80,21 +80,21 @@ public enum PeerReference: PostboxCoding, Hashable, Equatable {
switch flatBuffersObject.valueType {
case .peerreferenceUser:
guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_User.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .user(id: value.id, accessHash: value.accessHash)
case .peerreferenceGroup:
guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_Group.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .group(id: value.id)
case .peerreferenceChannel:
guard let value = flatBuffersObject.value(type: TelegramCore_PeerReference_Channel.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .channel(id: value.id, accessHash: value.accessHash)
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}

View File

@ -42,7 +42,7 @@ public final class RecentMediaItem: Codable, Equatable {
if let serializedFileData = try container.decodeIfPresent(Data.self, forKey: "md") {
self.serializedFile = serializedFileData
var byteBuffer = ByteBuffer(data: serializedFileData)
self.media = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
self.media = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
} else {
let mediaData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "m")
let media = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: mediaData.data)))
@ -282,7 +282,7 @@ public final class RecentReactionItem: Codable, Equatable {
if let mediaData = try container.decodeIfPresent(Data.self, forKey: "md") {
var byteBuffer = ByteBuffer(data: mediaData)
let file = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, mediaData)
let file = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, mediaData)
self.content = .custom(file)
} else if let mediaData = try container.decodeIfPresent(AdaptedPostboxDecoder.RawObjectData.self, forKey: "m") {
self.content = .custom(TelegramMediaFile.Accessor(TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: mediaData.data)))))

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
private enum RichTextTypes: Int32 {
case empty = 0
@ -292,3 +294,208 @@ public extension RichText {
}
}
}
extension RichText {
public init(flatBuffersObject: TelegramCore_RichText) throws {
switch flatBuffersObject.valueType {
case .richtextEmpty:
self = .empty
case .richtextPlain:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Plain.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .plain(value.text)
case .richtextBold:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Bold.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .bold(try RichText(flatBuffersObject: value.text))
case .richtextItalic:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Italic.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .italic(try RichText(flatBuffersObject: value.text))
case .richtextUnderline:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Underline.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .underline(try RichText(flatBuffersObject: value.text))
case .richtextStrikethrough:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Strikethrough.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .strikethrough(try RichText(flatBuffersObject: value.text))
case .richtextFixed:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Fixed.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .fixed(try RichText(flatBuffersObject: value.text))
case .richtextUrl:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Url.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .url(text: try RichText(flatBuffersObject: value.text), url: value.url, webpageId: value.webpageId.flatMap { MediaId($0) })
case .richtextEmail:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Email.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .email(text: try RichText(flatBuffersObject: value.text),
email: value.email)
case .richtextConcat:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Concat.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .concat(try (0..<value.textsCount).map { try RichText(flatBuffersObject: value.texts(at: $0)!) })
case .richtextSubscript:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Subscript.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .subscript(try RichText(flatBuffersObject: value.text))
case .richtextSuperscript:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Superscript.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .superscript(try RichText(flatBuffersObject: value.text))
case .richtextMarked:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Marked.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .marked(try RichText(flatBuffersObject: value.text))
case .richtextPhone:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Phone.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .phone(text: try RichText(flatBuffersObject: value.text),
phone: value.phone)
case .richtextImage:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Image.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .image(id: MediaId(value.id), dimensions: PixelDimensions(value.dimensions))
case .richtextAnchor:
guard let value = flatBuffersObject.value(type: TelegramCore_RichText_Anchor.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .anchor(text: try RichText(flatBuffersObject: value.text),
name: value.name)
case .none_:
self = .empty
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_RichText_Value
let offset: Offset
switch self {
case .empty:
valueType = .richtextEmpty
let start = TelegramCore_RichText_Empty.startRichText_Empty(&builder)
offset = TelegramCore_RichText_Empty.endRichText_Empty(&builder, start: start)
case let .plain(text):
valueType = .richtextPlain
let textOffset = builder.create(string: text)
let start = TelegramCore_RichText_Plain.startRichText_Plain(&builder)
TelegramCore_RichText_Plain.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Plain.endRichText_Plain(&builder, start: start)
case let .bold(text):
valueType = .richtextBold
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Bold.startRichText_Bold(&builder)
TelegramCore_RichText_Bold.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Bold.endRichText_Bold(&builder, start: start)
case let .italic(text):
valueType = .richtextItalic
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Italic.startRichText_Italic(&builder)
TelegramCore_RichText_Italic.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Italic.endRichText_Italic(&builder, start: start)
case let .underline(text):
valueType = .richtextUnderline
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Underline.startRichText_Underline(&builder)
TelegramCore_RichText_Underline.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Underline.endRichText_Underline(&builder, start: start)
case let .strikethrough(text):
valueType = .richtextStrikethrough
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Strikethrough.startRichText_Strikethrough(&builder)
TelegramCore_RichText_Strikethrough.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Strikethrough.endRichText_Strikethrough(&builder, start: start)
case let .fixed(text):
valueType = .richtextFixed
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Fixed.startRichText_Fixed(&builder)
TelegramCore_RichText_Fixed.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Fixed.endRichText_Fixed(&builder, start: start)
case let .url(text, url, webpageId):
valueType = .richtextUrl
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let urlOffset = builder.create(string: url)
let start = TelegramCore_RichText_Url.startRichText_Url(&builder)
TelegramCore_RichText_Url.add(text: textOffset, &builder)
TelegramCore_RichText_Url.add(url: urlOffset, &builder)
if let webpageId {
TelegramCore_RichText_Url.add(webpageId: webpageId.asFlatBuffersObject(), &builder)
}
offset = TelegramCore_RichText_Url.endRichText_Url(&builder, start: start)
case let .email(text, email):
valueType = .richtextEmail
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let emailOffset = builder.create(string: email)
let start = TelegramCore_RichText_Email.startRichText_Email(&builder)
TelegramCore_RichText_Email.add(text: textOffset, &builder)
TelegramCore_RichText_Email.add(email: emailOffset, &builder)
offset = TelegramCore_RichText_Email.endRichText_Email(&builder, start: start)
case let .concat(texts):
valueType = .richtextConcat
let textsOffsets = texts.map { $0.encodeToFlatBuffers(builder: &builder) }
let textsOffset = builder.createVector(ofOffsets: textsOffsets, len: textsOffsets.count)
let start = TelegramCore_RichText_Concat.startRichText_Concat(&builder)
TelegramCore_RichText_Concat.addVectorOf(texts: textsOffset, &builder)
offset = TelegramCore_RichText_Concat.endRichText_Concat(&builder, start: start)
case let .subscript(text):
valueType = .richtextSubscript
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Subscript.startRichText_Subscript(&builder)
TelegramCore_RichText_Subscript.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Subscript.endRichText_Subscript(&builder, start: start)
case let .superscript(text):
valueType = .richtextSuperscript
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Superscript.startRichText_Superscript(&builder)
TelegramCore_RichText_Superscript.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Superscript.endRichText_Superscript(&builder, start: start)
case let .marked(text):
valueType = .richtextMarked
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_RichText_Marked.startRichText_Marked(&builder)
TelegramCore_RichText_Marked.add(text: textOffset, &builder)
offset = TelegramCore_RichText_Marked.endRichText_Marked(&builder, start: start)
case let .phone(text, phone):
valueType = .richtextPhone
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let phoneOffset = builder.create(string: phone)
let start = TelegramCore_RichText_Phone.startRichText_Phone(&builder)
TelegramCore_RichText_Phone.add(text: textOffset, &builder)
TelegramCore_RichText_Phone.add(phone: phoneOffset, &builder)
offset = TelegramCore_RichText_Phone.endRichText_Phone(&builder, start: start)
case let .image(id, dimensions):
valueType = .richtextImage
let start = TelegramCore_RichText_Image.startRichText_Image(&builder)
TelegramCore_RichText_Image.add(id: id.asFlatBuffersObject(), &builder)
TelegramCore_RichText_Image.add(dimensions: dimensions.asFlatBuffersObject(), &builder)
offset = TelegramCore_RichText_Image.endRichText_Image(&builder, start: start)
case let .anchor(text, name):
valueType = .richtextAnchor
let textOffset = text.encodeToFlatBuffers(builder: &builder)
let nameOffset = builder.create(string: name)
let start = TelegramCore_RichText_Anchor.startRichText_Anchor(&builder)
TelegramCore_RichText_Anchor.add(text: textOffset, &builder)
TelegramCore_RichText_Anchor.add(name: nameOffset, &builder)
offset = TelegramCore_RichText_Anchor.endRichText_Anchor(&builder, start: start)
}
return TelegramCore_RichText.createRichText(&builder, valueType: valueType, valueOffset: offset)
}
}

View File

@ -17,7 +17,7 @@ public final class SavedStickerItem: Codable, Equatable {
if let serializedFileData = try container.decodeIfPresent(Data.self, forKey: "fd") {
var byteBuffer = ByteBuffer(data: serializedFileData)
self.file = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
self.file = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
} else {
let file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: (try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: "f")).data)))
self.file = TelegramMediaFile.Accessor(file)

View File

@ -18,7 +18,7 @@ public final class StickerPackItem: ItemCollectionItem, Equatable {
self.index = index
var byteBuffer = ByteBuffer(data: serializedFile)
let accessor = getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile
let accessor = FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile
self.file = TelegramMediaFile.Accessor(accessor, serializedFile)
self.indexKeys = indexKeys
@ -29,7 +29,7 @@ public final class StickerPackItem: ItemCollectionItem, Equatable {
if let serializedFileData = decoder.decodeDataForKey("fd") {
var byteBuffer = ByteBuffer(data: serializedFileData)
self.file = TelegramMediaFile.Accessor(getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
self.file = TelegramMediaFile.Accessor(FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramMediaFile, serializedFileData)
} else {
let file = decoder.decodeObjectForKey("f") as! TelegramMediaFile
self.file = TelegramMediaFile.Accessor(file)

View File

@ -1,31 +1,22 @@
import Postbox
import FlatBuffers
import FlatSerialization
public enum TelegramChannelParticipationStatus {
case member
case left
case kicked
public enum TelegramChannelParticipationStatus: Int32 {
case member = 0
case left = 1
case kicked = 2
fileprivate var rawValue: Int32 {
switch self {
case .member:
return 0
case .left:
return 1
case .kicked:
return 2
}
}
fileprivate init(rawValue: Int32) {
public init(rawValue: Int32) {
switch rawValue {
case 0:
self = .member
case 1:
self = .left
case 2:
self = .kicked
default:
self = .left
case 0:
self = .member
case 1:
self = .left
case 2:
self = .kicked
default:
self = .left
}
}
}
@ -48,6 +39,7 @@ public struct TelegramChannelBroadcastFlags: OptionSet {
public struct TelegramChannelBroadcastInfo: Equatable {
public let flags: TelegramChannelBroadcastFlags
public init(flags: TelegramChannelBroadcastFlags) {
self.flags = flags
}
@ -124,6 +116,46 @@ public enum TelegramChannelInfo: Equatable {
return .group(TelegramChannelGroupInfo(flags: TelegramChannelGroupFlags(rawValue: decoder.decodeInt32ForKey("i.f", orElse: 0))))
}
}
public init(flatBuffersObject: TelegramCore_TelegramChannelInfo) throws {
switch flatBuffersObject.valueType {
case .telegramchannelinfoBroadcast:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramChannelInfo_Broadcast.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .broadcast(TelegramChannelBroadcastInfo(flags: TelegramChannelBroadcastFlags(rawValue: value.flags)))
case .telegramchannelinfoGroup:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramChannelInfo_Group.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .group(TelegramChannelGroupInfo(flags: TelegramChannelGroupFlags(rawValue: value.flags)))
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueType: TelegramCore_TelegramChannelInfo_Value
let valueOffset: Offset
switch self {
case let .broadcast(info):
valueType = .telegramchannelinfoBroadcast
let start = TelegramCore_TelegramChannelInfo_Broadcast.startTelegramChannelInfo_Broadcast(&builder)
TelegramCore_TelegramChannelInfo_Broadcast.add(flags: info.flags.rawValue, &builder)
valueOffset = TelegramCore_TelegramChannelInfo_Broadcast.endTelegramChannelInfo_Broadcast(&builder, start: start)
case let .group(info):
valueType = .telegramchannelinfoGroup
let start = TelegramCore_TelegramChannelInfo_Group.startTelegramChannelInfo_Group(&builder)
TelegramCore_TelegramChannelInfo_Group.add(flags: info.flags.rawValue, &builder)
valueOffset = TelegramCore_TelegramChannelInfo_Group.endTelegramChannelInfo_Group(&builder, start: start)
}
let start = TelegramCore_TelegramChannelInfo.startTelegramChannelInfo(&builder)
TelegramCore_TelegramChannelInfo.add(valueType: valueType, &builder)
TelegramCore_TelegramChannelInfo.add(value: valueOffset, &builder)
return TelegramCore_TelegramChannelInfo.endTelegramChannelInfo(&builder, start: start)
}
}
public struct TelegramChannelFlags: OptionSet {
@ -314,6 +346,17 @@ public final class TelegramChannel: Peer, Equatable {
self.subscriptionUntilDate = decoder.decodeOptionalInt32ForKey("sud")
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
self.sendPaidMessageStars = decoder.decodeCodable(StarsAmount.self, forKey: "sendPaidMessageStars")
#if DEBUG
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)
let serializedData = builder.data
var byteBuffer = ByteBuffer(data: serializedData)
let deserializedValue = FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramChannel
let parsedValue = try! TelegramChannel(flatBuffersObject: deserializedValue)
assert(self == parsedValue)
#endif
}
public func encode(_ encoder: PostboxEncoder) {
@ -544,4 +587,116 @@ public final class TelegramChannel: Peer, Equatable {
public func withUpdatedVerificationIconFileId(_ verificationIconFileId: Int64?) -> TelegramChannel {
return TelegramChannel(id: self.id, accessHash: self.accessHash, title: self.title, username: self.username, photo: self.photo, creationDate: self.creationDate, version: self.version, participationStatus: self.participationStatus, info: self.info, flags: self.flags, restrictionInfo: self.restrictionInfo, adminRights: self.adminRights, bannedRights: self.bannedRights, defaultBannedRights: self.defaultBannedRights, usernames: self.usernames, storiesHidden: self.storiesHidden, nameColor: self.nameColor, backgroundEmojiId: self.backgroundEmojiId, profileColor: self.profileColor, profileBackgroundEmojiId: self.profileBackgroundEmojiId, emojiStatus: self.emojiStatus, approximateBoostLevel: self.approximateBoostLevel, subscriptionUntilDate: self.subscriptionUntilDate, verificationIconFileId: verificationIconFileId, sendPaidMessageStars: self.sendPaidMessageStars)
}
public init(flatBuffersObject: TelegramCore_TelegramChannel) throws {
self.id = PeerId(flatBuffersObject.id)
self.accessHash = try flatBuffersObject.accessHash.flatMap(TelegramPeerAccessHash.init)
self.title = flatBuffersObject.title
self.username = flatBuffersObject.username
self.photo = try (0 ..< flatBuffersObject.photoCount).map { try TelegramMediaImageRepresentation(flatBuffersObject: flatBuffersObject.photo(at: $0)!) }
self.creationDate = flatBuffersObject.creationDate
self.version = flatBuffersObject.version
self.participationStatus = TelegramChannelParticipationStatus(rawValue: flatBuffersObject.participationStatus)
guard let infoObj = flatBuffersObject.info else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self.info = try TelegramChannelInfo(flatBuffersObject: infoObj)
self.flags = TelegramChannelFlags(rawValue: flatBuffersObject.flags)
self.restrictionInfo = try flatBuffersObject.restrictionInfo.flatMap { try PeerAccessRestrictionInfo(flatBuffersObject: $0) }
self.adminRights = try flatBuffersObject.adminRights.flatMap { try TelegramChatAdminRights(flatBuffersObject: $0) }
self.bannedRights = try flatBuffersObject.bannedRights.flatMap { try TelegramChatBannedRights(flatBuffersObject: $0) }
self.defaultBannedRights = try flatBuffersObject.defaultBannedRights.map { try TelegramChatBannedRights(flatBuffersObject: $0) }
self.usernames = try (0 ..< flatBuffersObject.usernamesCount).map { try TelegramPeerUsername(flatBuffersObject: flatBuffersObject.usernames(at: $0)!) }
self.storiesHidden = flatBuffersObject.storiesHidden?.value
self.nameColor = try flatBuffersObject.nameColor.flatMap(PeerNameColor.init(flatBuffersObject:))
self.backgroundEmojiId = flatBuffersObject.backgroundEmojiId == Int64.min ? nil : flatBuffersObject.backgroundEmojiId
self.profileColor = try flatBuffersObject.profileColor.flatMap(PeerNameColor.init)
self.profileBackgroundEmojiId = flatBuffersObject.profileBackgroundEmojiId == Int64.min ? nil : flatBuffersObject.profileBackgroundEmojiId
self.emojiStatus = try flatBuffersObject.emojiStatus.flatMap { try PeerEmojiStatus(flatBuffersObject: $0) }
self.approximateBoostLevel = flatBuffersObject.approximateBoostLevel == Int32.min ? nil : flatBuffersObject.approximateBoostLevel
self.subscriptionUntilDate = flatBuffersObject.subscriptionUntilDate == Int32.min ? nil : flatBuffersObject.subscriptionUntilDate
self.verificationIconFileId = flatBuffersObject.verificationIconFileId == Int64.min ? nil : flatBuffersObject.verificationIconFileId
self.sendPaidMessageStars = try flatBuffersObject.sendPaidMessageStars.flatMap { try StarsAmount(flatBuffersObject: $0) }
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let accessHashOffset = self.accessHash.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let photoOffsets = self.photo.map { $0.encodeToFlatBuffers(builder: &builder) }
let photoOffset = builder.createVector(ofOffsets: photoOffsets, len: photoOffsets.count)
let usernamesOffsets = self.usernames.map { $0.encodeToFlatBuffers(builder: &builder) }
let usernamesOffset = builder.createVector(ofOffsets: usernamesOffsets, len: usernamesOffsets.count)
let titleOffset = builder.create(string: self.title)
let usernameOffset = self.username.map { builder.create(string: $0) }
let nameColorOffset = self.nameColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let profileColorOffset = self.profileColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let infoOffset = self.info.encodeToFlatBuffers(builder: &builder)
let restrictionInfoOffset = self.restrictionInfo?.encodeToFlatBuffers(builder: &builder)
let adminRightsOffset = self.adminRights?.encodeToFlatBuffers(builder: &builder)
let bannedRightsOffset = self.bannedRights?.encodeToFlatBuffers(builder: &builder)
let defaultBannedRightsOffset = self.defaultBannedRights?.encodeToFlatBuffers(builder: &builder)
let emojiStatusOffset = self.emojiStatus?.encodeToFlatBuffers(builder: &builder)
let sendPaidMessageStarsOffset = self.sendPaidMessageStars?.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_TelegramChannel.startTelegramChannel(&builder)
TelegramCore_TelegramChannel.add(id: self.id.asFlatBuffersObject(), &builder)
if let accessHashOffset {
TelegramCore_TelegramChannel.add(accessHash: accessHashOffset, &builder)
}
TelegramCore_TelegramChannel.add(title: titleOffset, &builder)
if let usernameOffset {
TelegramCore_TelegramChannel.add(username: usernameOffset, &builder)
}
TelegramCore_TelegramChannel.addVectorOf(photo: photoOffset, &builder)
TelegramCore_TelegramChannel.add(creationDate: self.creationDate, &builder)
TelegramCore_TelegramChannel.add(version: self.version, &builder)
TelegramCore_TelegramChannel.add(participationStatus: self.participationStatus.rawValue, &builder)
TelegramCore_TelegramChannel.add(info: infoOffset, &builder)
TelegramCore_TelegramChannel.add(flags: self.flags.rawValue, &builder)
if let restrictionInfoOffset {
TelegramCore_TelegramChannel.add(restrictionInfo: restrictionInfoOffset, &builder)
}
if let adminRightsOffset {
TelegramCore_TelegramChannel.add(adminRights: adminRightsOffset, &builder)
}
if let bannedRightsOffset {
TelegramCore_TelegramChannel.add(bannedRights: bannedRightsOffset, &builder)
}
if let defaultBannedRightsOffset {
TelegramCore_TelegramChannel.add(defaultBannedRights: defaultBannedRightsOffset, &builder)
}
TelegramCore_TelegramChannel.addVectorOf(usernames: usernamesOffset, &builder)
if let storiesHidden = self.storiesHidden {
TelegramCore_TelegramChannel.add(storiesHidden: TelegramCore_OptionalBool(value: storiesHidden), &builder)
}
if let nameColorOffset {
TelegramCore_TelegramChannel.add(nameColor: nameColorOffset, &builder)
}
TelegramCore_TelegramChannel.add(backgroundEmojiId: self.backgroundEmojiId ?? Int64.min, &builder)
if let profileColorOffset {
TelegramCore_TelegramChannel.add(profileColor: profileColorOffset, &builder)
}
TelegramCore_TelegramChannel.add(profileBackgroundEmojiId: self.profileBackgroundEmojiId ?? Int64.min, &builder)
if let emojiStatusOffset {
TelegramCore_TelegramChannel.add(emojiStatus: emojiStatusOffset, &builder)
}
TelegramCore_TelegramChannel.add(approximateBoostLevel: self.approximateBoostLevel ?? Int32.min, &builder)
TelegramCore_TelegramChannel.add(subscriptionUntilDate: self.subscriptionUntilDate ?? Int32.min, &builder)
TelegramCore_TelegramChannel.add(verificationIconFileId: self.verificationIconFileId ?? Int64.min, &builder)
if let sendPaidMessageStarsOffset {
TelegramCore_TelegramChannel.add(sendPaidMessageStars: sendPaidMessageStarsOffset, &builder)
}
return TelegramCore_TelegramChannel.endTelegramChannel(&builder, start: start)
}
}

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
public struct TelegramChatAdminRightsFlags: OptionSet, Hashable {
public var rawValue: Int32
@ -124,4 +126,14 @@ public struct TelegramChatAdminRights: PostboxCoding, Codable, Equatable {
public static func ==(lhs: TelegramChatAdminRights, rhs: TelegramChatAdminRights) -> Bool {
return lhs.rights == rhs.rights
}
public init(flatBuffersObject: TelegramCore_TelegramChatAdminRights) throws {
self.rights = TelegramChatAdminRightsFlags(rawValue: flatBuffersObject.rights)
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let start = TelegramCore_TelegramChatAdminRights.startTelegramChatAdminRights(&builder)
TelegramCore_TelegramChatAdminRights.add(rights: self.rights.rawValue, &builder)
return TelegramCore_TelegramChatAdminRights.endTelegramChatAdminRights(&builder, start: start)
}
}

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
public struct TelegramChatBannedRightsFlags: OptionSet, Hashable {
public var rawValue: Int32
@ -54,4 +56,16 @@ public struct TelegramChatBannedRights: PostboxCoding, Equatable {
public static func ==(lhs: TelegramChatBannedRights, rhs: TelegramChatBannedRights) -> Bool {
return lhs.flags == rhs.flags && lhs.untilDate == rhs.untilDate
}
public init(flatBuffersObject: TelegramCore_TelegramChatBannedRights) throws {
self.flags = TelegramChatBannedRightsFlags(rawValue: flatBuffersObject.flags)
self.untilDate = flatBuffersObject.untilDate
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let start = TelegramCore_TelegramChatBannedRights.startTelegramChatBannedRights(&builder)
TelegramCore_TelegramChatBannedRights.add(flags: self.flags.rawValue, &builder)
TelegramCore_TelegramChatBannedRights.add(untilDate: self.untilDate, &builder)
return TelegramCore_TelegramChatBannedRights.endTelegramChatBannedRights(&builder, start: start)
}
}

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
public enum TelegramGroupRole: Equatable, PostboxCoding {
case creator(rank: String?)
@ -40,6 +42,61 @@ public enum TelegramGroupRole: Equatable, PostboxCoding {
encoder.encodeInt32(2, forKey: "_v")
}
}
public init(flatBuffersObject: TelegramCore_TelegramGroupRole) throws {
switch flatBuffersObject.valueType {
case .telegramgrouproleCreator:
guard let creator = flatBuffersObject.value(type: TelegramCore_TelegramGroupRole_Creator.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .creator(rank: creator.rank)
case .telegramgrouproleAdmin:
guard let admin = flatBuffersObject.value(type: TelegramCore_TelegramGroupRole_Admin.self) else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .admin(try TelegramChatAdminRights(flatBuffersObject: admin.rights), rank: admin.rank)
case .telegramgrouproleMember:
self = .member
case .none_:
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let valueOffset: Offset
let valueType: TelegramCore_TelegramGroupRole_Value
switch self {
case let .creator(rank):
let rankOffset = rank.map { builder.create(string: $0) }
let start = TelegramCore_TelegramGroupRole_Creator.startTelegramGroupRole_Creator(&builder)
if let rankOffset {
TelegramCore_TelegramGroupRole_Creator.add(rank: rankOffset, &builder)
}
valueOffset = TelegramCore_TelegramGroupRole_Creator.endTelegramGroupRole_Creator(&builder, start: start)
valueType = .telegramgrouproleCreator
case let .admin(rights, rank):
let rankOffset = rank.map { builder.create(string: $0) }
let rightsOffset = rights.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_TelegramGroupRole_Admin.startTelegramGroupRole_Admin(&builder)
TelegramCore_TelegramGroupRole_Admin.add(rights: rightsOffset, &builder)
if let rankOffset {
TelegramCore_TelegramGroupRole_Admin.add(rank: rankOffset, &builder)
}
valueOffset = TelegramCore_TelegramGroupRole_Admin.endTelegramGroupRole_Admin(&builder, start: start)
valueType = .telegramgrouproleAdmin
case .member:
let start = TelegramCore_TelegramGroupRole_Member.startTelegramGroupRole_Member(&builder)
valueOffset = TelegramCore_TelegramGroupRole_Member.endTelegramGroupRole_Member(&builder, start: start)
valueType = .telegramgrouproleMember
}
let start = TelegramCore_TelegramGroupRole.startTelegramGroupRole(&builder)
TelegramCore_TelegramGroupRole.add(value: valueOffset, &builder)
TelegramCore_TelegramGroupRole.add(valueType: valueType, &builder)
return TelegramCore_TelegramGroupRole.endTelegramGroupRole(&builder, start: start)
}
}
public enum TelegramGroupMembership: Int32 {
@ -73,6 +130,18 @@ public struct TelegramGroupToChannelMigrationReference: Equatable {
self.peerId = peerId
self.accessHash = accessHash
}
public init(flatBuffersObject: TelegramCore_TelegramGroupToChannelMigrationReference) throws {
self.peerId = PeerId(flatBuffersObject.peerId)
self.accessHash = flatBuffersObject.accessHash
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let start = TelegramCore_TelegramGroupToChannelMigrationReference.startTelegramGroupToChannelMigrationReference(&builder)
TelegramCore_TelegramGroupToChannelMigrationReference.add(peerId: self.peerId.toInt64(), &builder)
TelegramCore_TelegramGroupToChannelMigrationReference.add(accessHash: self.accessHash, &builder)
return TelegramCore_TelegramGroupToChannelMigrationReference.endTelegramGroupToChannelMigrationReference(&builder, start: start)
}
}
public final class TelegramGroup: Peer, Equatable {
@ -137,6 +206,17 @@ public final class TelegramGroup: Peer, Equatable {
}
self.creationDate = decoder.decodeInt32ForKey("d", orElse: 0)
self.version = Int(decoder.decodeInt32ForKey("v", orElse: 0))
#if DEBUG
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)
let serializedData = builder.data
var byteBuffer = ByteBuffer(data: serializedData)
let deserializedValue = FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramGroup
let parsedValue = try! TelegramGroup(flatBuffersObject: deserializedValue)
assert(self == parsedValue)
#endif
}
public func encode(_ encoder: PostboxEncoder) {
@ -162,6 +242,65 @@ public final class TelegramGroup: Peer, Equatable {
encoder.encodeInt32(self.creationDate, forKey: "d")
encoder.encodeInt32(Int32(self.version), forKey: "v")
}
public init(flatBuffersObject: TelegramCore_TelegramGroup) throws {
self.id = PeerId(flatBuffersObject.id)
self.title = flatBuffersObject.title
self.photo = try (0 ..< flatBuffersObject.photoCount).map { try TelegramMediaImageRepresentation(flatBuffersObject: flatBuffersObject.photo(at: $0)!) }
self.participantCount = Int(flatBuffersObject.participantCount)
guard let role = flatBuffersObject.role else {
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self.role = try TelegramGroupRole(flatBuffersObject: role)
self.membership = TelegramGroupMembership(rawValue: flatBuffersObject.membership)!
self.flags = TelegramGroupFlags(rawValue: flatBuffersObject.flags)
self.defaultBannedRights = try flatBuffersObject.defaultBannedRights.flatMap { try TelegramChatBannedRights(flatBuffersObject: $0) }
if let migrationReference = flatBuffersObject.migrationReference {
self.migrationReference = try TelegramGroupToChannelMigrationReference(flatBuffersObject: migrationReference)
} else {
self.migrationReference = nil
}
self.creationDate = flatBuffersObject.creationDate
self.version = Int(flatBuffersObject.version)
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let titleOffset = builder.create(string: self.title)
let photoOffsets = self.photo.map { $0.encodeToFlatBuffers(builder: &builder) }
let photoOffset = builder.createVector(ofOffsets: photoOffsets, len: photoOffsets.count)
let roleOffset = self.role.encodeToFlatBuffers(builder: &builder)
let defaultBannedRightsOffset = self.defaultBannedRights?.encodeToFlatBuffers(builder: &builder)
let migrationReferenceOffset = self.migrationReference?.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_TelegramGroup.startTelegramGroup(&builder)
TelegramCore_TelegramGroup.add(id: self.id.asFlatBuffersObject(), &builder)
TelegramCore_TelegramGroup.add(title: titleOffset, &builder)
TelegramCore_TelegramGroup.addVectorOf(photo: photoOffset, &builder)
TelegramCore_TelegramGroup.add(participantCount: Int32(self.participantCount), &builder)
TelegramCore_TelegramGroup.add(role: roleOffset, &builder)
TelegramCore_TelegramGroup.add(membership: self.membership.rawValue, &builder)
TelegramCore_TelegramGroup.add(flags: self.flags.rawValue, &builder)
if let defaultBannedRightsOffset {
TelegramCore_TelegramGroup.add(defaultBannedRights: defaultBannedRightsOffset, &builder)
}
if let migrationReferenceOffset {
TelegramCore_TelegramGroup.add(migrationReference: migrationReferenceOffset, &builder)
}
TelegramCore_TelegramGroup.add(creationDate: self.creationDate, &builder)
TelegramCore_TelegramGroup.add(version: Int32(self.version), &builder)
return TelegramCore_TelegramGroup.endTelegramGroup(&builder, start: start)
}
public func isEqual(_ other: Peer) -> Bool {
if let other = other as? TelegramGroup {

View File

@ -15,11 +15,6 @@ 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)
@ -131,19 +126,19 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
switch flatBuffersObject.valueType {
case .stickerpackreferenceId:
guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Id.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .id(id: value.id, accessHash: value.accessHash)
case .stickerpackreferenceName:
guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Name.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .name(value.name)
case .stickerpackreferenceAnimatedemoji:
self = .animatedEmoji
case .stickerpackreferenceDice:
guard let value = flatBuffersObject.value(type: TelegramCore_StickerPackReference_Dice.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .dice(value.emoji)
case .stickerpackreferenceAnimatedemojianimations:
@ -159,7 +154,7 @@ public enum StickerPackReference: PostboxCoding, Hashable, Equatable, Codable {
case .stickerpackreferenceIconchannelstatusemoji:
self = .iconChannelStatusEmoji
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
}
@ -475,7 +470,7 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
init(flatBuffersData data: Data) throws {
var byteBuffer = ByteBuffer(data: data)
let flatBuffersObject: TelegramCore_TelegramMediaFileAttribute = getRoot(byteBuffer: &byteBuffer)
let flatBuffersObject: TelegramCore_TelegramMediaFileAttribute = FlatBuffers_getRoot(byteBuffer: &byteBuffer)
try self.init(flatBuffersObject: flatBuffersObject)
}
@ -483,29 +478,29 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
switch flatBuffersObject.valueType {
case .telegrammediafileattributeFilename:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_FileName.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .FileName(fileName: value.fileName)
case .telegrammediafileattributeSticker:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_Sticker.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
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
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
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
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
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
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
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:
@ -517,10 +512,10 @@ public enum TelegramMediaFileAttribute: PostboxCoding, Equatable {
case .telegrammediafileattributeNopremium:
self = .NoPremium
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
case .telegrammediafileattributeCustomemoji:
guard let value = flatBuffersObject.value(type: TelegramCore_TelegramMediaFileAttribute_CustomEmoji.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self = .CustomEmoji(isPremium: value.isPremium, isSingleColor: value.isSingleColor, alt: value.alt, packReference: try value.packReference.flatMap({ try StickerPackReference(flatBuffersObject: $0) }))
}

View File

@ -219,16 +219,16 @@ public final class TelegramMediaImage: Media, Equatable, Codable {
switch flatBuffersObject.contentType {
case .emojimarkupContentEmoji:
guard let value = flatBuffersObject.content(type: TelegramCore_EmojiMarkup_Content_Emoji.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self.content = .emoji(fileId: value.fileId)
case .emojimarkupContentSticker:
guard let value = flatBuffersObject.content(type: TelegramCore_EmojiMarkup_Content_Sticker.self) else {
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self.content = .sticker(packReference: try StickerPackReference(flatBuffersObject: value.packReference), fileId: value.fileId)
case .none_:
throw FlatBuffersError.missingRequiredField
throw FlatBuffersError.missingRequiredField(file: #file, line: #line)
}
self.backgroundColors = flatBuffersObject.backgroundColors

View File

@ -1,4 +1,6 @@
import Postbox
import FlatBuffers
import FlatSerialization
public struct UserInfoFlags: OptionSet {
public var rawValue: Int32
@ -64,6 +66,22 @@ public struct BotUserInfo: PostboxCoding, Equatable {
encoder.encodeNil(forKey: "ip")
}
}
public init(flatBuffersObject: TelegramCore_BotUserInfo) throws {
self.flags = BotUserInfoFlags(rawValue: flatBuffersObject.flags)
self.inlinePlaceholder = flatBuffersObject.inlinePlaceholder
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let inlinePlaceholderOffset = self.inlinePlaceholder.map { builder.create(string: $0) }
let start = TelegramCore_BotUserInfo.startBotUserInfo(&builder)
TelegramCore_BotUserInfo.add(flags: self.flags.rawValue, &builder)
if let inlinePlaceholderOffset {
TelegramCore_BotUserInfo.add(inlinePlaceholder: inlinePlaceholderOffset, &builder)
}
return TelegramCore_BotUserInfo.endBotUserInfo(&builder, start: start)
}
}
public struct TelegramPeerUsername: PostboxCoding, Equatable {
@ -99,6 +117,20 @@ public struct TelegramPeerUsername: PostboxCoding, Equatable {
encoder.encodeInt32(self.flags.rawValue, forKey: "f")
encoder.encodeString(self.username, forKey: "un")
}
public init(flatBuffersObject: TelegramCore_TelegramPeerUsername) throws {
self.flags = Flags(rawValue: flatBuffersObject.flags)
self.username = flatBuffersObject.username
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let usernameOffset = builder.create(string: self.username)
let start = TelegramCore_TelegramPeerUsername.startTelegramPeerUsername(&builder)
TelegramCore_TelegramPeerUsername.add(flags: self.flags.rawValue, &builder)
TelegramCore_TelegramPeerUsername.add(username: usernameOffset, &builder)
return TelegramCore_TelegramPeerUsername.endTelegramPeerUsername(&builder, start: start)
}
}
public struct PeerVerification: Codable, Equatable {
@ -298,6 +330,17 @@ public final class TelegramUser: Peer, Equatable {
self.profileBackgroundEmojiId = decoder.decodeOptionalInt64ForKey("pgem")
self.subscriberCount = decoder.decodeOptionalInt32ForKey("ssc")
self.verificationIconFileId = decoder.decodeOptionalInt64ForKey("vfid")
#if DEBUG
var builder = FlatBufferBuilder(initialSize: 1024)
let offset = self.encodeToFlatBuffers(builder: &builder)
builder.finish(offset: offset)
let serializedData = builder.data
var byteBuffer = ByteBuffer(data: serializedData)
let deserializedValue = FlatBuffers_getRoot(byteBuffer: &byteBuffer) as TelegramCore_TelegramUser
let parsedValue = try! TelegramUser(flatBuffersObject: deserializedValue)
assert(self == parsedValue)
#endif
}
public func encode(_ encoder: PostboxEncoder) {
@ -516,4 +559,95 @@ public final class TelegramUser: Peer, Equatable {
public func withUpdatedProfileBackgroundEmojiId(_ profileBackgroundEmojiId: Int64?) -> TelegramUser {
return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: self.username, phone: self.phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags, emojiStatus: self.emojiStatus, usernames: self.usernames, storiesHidden: self.storiesHidden, nameColor: self.nameColor, backgroundEmojiId: self.backgroundEmojiId, profileColor: self.profileColor, profileBackgroundEmojiId: profileBackgroundEmojiId, subscriberCount: self.subscriberCount, verificationIconFileId: self.verificationIconFileId)
}
public init(flatBuffersObject: TelegramCore_TelegramUser) throws {
self.id = PeerId(flatBuffersObject.id)
self.accessHash = try flatBuffersObject.accessHash.flatMap(TelegramPeerAccessHash.init)
self.firstName = flatBuffersObject.firstName
self.lastName = flatBuffersObject.lastName
self.username = flatBuffersObject.username
self.phone = flatBuffersObject.phone
self.photo = try (0 ..< flatBuffersObject.photoCount).map { try TelegramMediaImageRepresentation(flatBuffersObject: flatBuffersObject.photo(at: $0)!) }
self.botInfo = try flatBuffersObject.botInfo.flatMap { try BotUserInfo(flatBuffersObject: $0) }
self.restrictionInfo = try flatBuffersObject.restrictionInfo.flatMap { try PeerAccessRestrictionInfo(flatBuffersObject: $0) }
self.flags = UserInfoFlags(rawValue: flatBuffersObject.flags)
self.emojiStatus = try flatBuffersObject.emojiStatus.flatMap { try PeerEmojiStatus(flatBuffersObject: $0) }
self.usernames = try (0 ..< flatBuffersObject.usernamesCount).map { try TelegramPeerUsername(flatBuffersObject: flatBuffersObject.usernames(at: $0)!) }
self.storiesHidden = flatBuffersObject.storiesHidden?.value
self.nameColor = try flatBuffersObject.nameColor.flatMap(PeerNameColor.init)
self.backgroundEmojiId = flatBuffersObject.backgroundEmojiId == Int64.min ? nil : flatBuffersObject.backgroundEmojiId
self.profileColor = try flatBuffersObject.profileColor.flatMap(PeerNameColor.init)
self.profileBackgroundEmojiId = flatBuffersObject.profileBackgroundEmojiId == Int64.min ? nil : flatBuffersObject.profileBackgroundEmojiId
self.subscriberCount = flatBuffersObject.subscriberCount == Int32.min ? nil : flatBuffersObject.subscriberCount
self.verificationIconFileId = flatBuffersObject.verificationIconFileId == Int64.min ? nil : flatBuffersObject.verificationIconFileId
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let accessHashOffset = self.accessHash.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let firstNameOffset = self.firstName.map { builder.create(string: $0) }
let lastNameOffset = self.lastName.map { builder.create(string: $0) }
let usernameOffset = self.username.map { builder.create(string: $0) }
let phoneOffset = self.phone.map { builder.create(string: $0) }
let photoOffsets = self.photo.map { $0.encodeToFlatBuffers(builder: &builder) }
let photoOffset = builder.createVector(ofOffsets: photoOffsets, len: photoOffsets.count)
let botInfoOffset = self.botInfo?.encodeToFlatBuffers(builder: &builder)
let restrictionInfoOffset = self.restrictionInfo?.encodeToFlatBuffers(builder: &builder)
let usernamesOffsets = self.usernames.map { $0.encodeToFlatBuffers(builder: &builder) }
let usernamesOffset = builder.createVector(ofOffsets: usernamesOffsets, len: usernamesOffsets.count)
let nameColorOffset = self.nameColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let profileColorOffset = self.profileColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) }
let emojiStatusOffset = self.emojiStatus?.encodeToFlatBuffers(builder: &builder)
let start = TelegramCore_TelegramUser.startTelegramUser(&builder)
TelegramCore_TelegramUser.add(id: self.id.asFlatBuffersObject(), &builder)
if let accessHashOffset {
TelegramCore_TelegramUser.add(accessHash: accessHashOffset, &builder)
}
if let firstNameOffset {
TelegramCore_TelegramUser.add(firstName: firstNameOffset, &builder)
}
if let lastNameOffset {
TelegramCore_TelegramUser.add(lastName: lastNameOffset, &builder)
}
if let usernameOffset {
TelegramCore_TelegramUser.add(username: usernameOffset, &builder)
}
if let phoneOffset {
TelegramCore_TelegramUser.add(phone: phoneOffset, &builder)
}
TelegramCore_TelegramUser.addVectorOf(photo: photoOffset, &builder)
if let botInfoOffset {
TelegramCore_TelegramUser.add(botInfo: botInfoOffset, &builder)
}
if let restrictionInfoOffset {
TelegramCore_TelegramUser.add(restrictionInfo: restrictionInfoOffset, &builder)
}
TelegramCore_TelegramUser.add(flags: self.flags.rawValue, &builder)
if let emojiStatusOffset {
TelegramCore_TelegramUser.add(emojiStatus: emojiStatusOffset, &builder)
}
TelegramCore_TelegramUser.addVectorOf(usernames: usernamesOffset, &builder)
if let storiesHidden = self.storiesHidden {
TelegramCore_TelegramUser.add(storiesHidden: TelegramCore_OptionalBool(value: storiesHidden), &builder)
}
if let nameColorOffset {
TelegramCore_TelegramUser.add(nameColor: nameColorOffset, &builder)
}
TelegramCore_TelegramUser.add(backgroundEmojiId: self.backgroundEmojiId ?? Int64.min, &builder)
if let profileColorOffset {
TelegramCore_TelegramUser.add(profileColor: profileColorOffset, &builder)
}
TelegramCore_TelegramUser.add(profileBackgroundEmojiId: self.profileBackgroundEmojiId ?? Int64.min, &builder)
TelegramCore_TelegramUser.add(subscriberCount: self.subscriberCount ?? Int32.min, &builder)
TelegramCore_TelegramUser.add(verificationIconFileId: self.verificationIconFileId ?? Int64.min, &builder)
return TelegramCore_TelegramUser.endTelegramUser(&builder, start: start)
}
}

View File

@ -3,6 +3,8 @@ import Postbox
import MtProtoKit
import SwiftSignalKit
import TelegramApi
import FlatBuffers
import FlatSerialization
public struct StarsTopUpOption: Equatable, Codable {
enum CodingKeys: String, CodingKey {
@ -280,6 +282,18 @@ public struct StarsAmount: Equatable, Comparable, Hashable, Codable, CustomStrin
self.nanos = nanos
}
public init(flatBuffersObject: TelegramCore_StarsAmount) throws {
self.value = flatBuffersObject.value
self.nanos = flatBuffersObject.nanos
}
public func encodeToFlatBuffers(builder: inout FlatBufferBuilder) -> Offset {
let start = TelegramCore_StarsAmount.startStarsAmount(&builder)
TelegramCore_StarsAmount.add(value: self.value, &builder)
TelegramCore_StarsAmount.add(nanos: self.nanos, &builder)
return TelegramCore_StarsAmount.endStarsAmount(&builder, start: start)
}
public var stringValue: String {
return totalValue.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", totalValue) : String(format: "%.02f", totalValue)
}

View File

@ -0,0 +1,54 @@
import Foundation
import FlatBuffers
import FlatSerialization
import Postbox
#if DEBUG && false
public func FlatBuffers_getRoot<T: FlatBufferObject & Verifiable>(
byteBuffer: inout ByteBuffer,
fileId: String? = nil,
options: VerifierOptions = .init()
) -> T {
return try! getCheckedRoot(byteBuffer: &byteBuffer, fileId: fileId, options: options)
}
#else
@inline(__always)
public func FlatBuffers_getRoot<T: FlatBufferObject>(byteBuffer: inout ByteBuffer) -> T {
return getRoot(byteBuffer: &byteBuffer)
}
#endif
public enum FlatBuffersError: Error {
case missingRequiredField(file: String, line: Int)
case invalidUnionType
}
public extension PeerId {
init(_ id: TelegramCore_PeerId) {
self.init(namespace: PeerId.Namespace._internalFromInt32Value(id.namespace), id: PeerId.Id._internalFromInt64Value(id.id))
}
func asFlatBuffersObject() -> TelegramCore_PeerId {
return TelegramCore_PeerId(namespace: self.namespace._internalGetInt32Value(), id: self.id._internalGetInt64Value())
}
}
public extension MediaId {
init(_ id: TelegramCore_MediaId) {
self.init(namespace: id.namespace, id: id.id)
}
func asFlatBuffersObject() -> TelegramCore_MediaId {
return TelegramCore_MediaId(namespace: self.namespace, id: self.id)
}
}
public extension PixelDimensions {
init(_ dimensions: TelegramCore_PixelDimensions) {
self.init(width: dimensions.width, height: dimensions.height)
}
func asFlatBuffersObject() -> TelegramCore_PixelDimensions {
return TelegramCore_PixelDimensions(width: self.width, height: self.height)
}
}

View File

@ -0,0 +1,22 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "BatchVideoRendering",
module_name = "BatchVideoRendering",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/Display",
"//submodules/AccountContext",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramCore",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,341 @@
import Foundation
import UIKit
import Display
import UniversalMediaPlayer
import AccountContext
import SwiftSignalKit
import TelegramCore
import CoreMedia
public protocol BatchVideoRenderingContextTarget: AnyObject {
var batchVideoRenderingTargetState: BatchVideoRenderingContext.TargetState? { get set }
func setSampleBuffer(sampleBuffer: CMSampleBuffer)
}
public final class BatchVideoRenderingContext {
public typealias Target = BatchVideoRenderingContextTarget
public final class TargetHandle {
private weak var context: BatchVideoRenderingContext?
private let id: Int
init(context: BatchVideoRenderingContext, id: Int) {
self.context = context
self.id = id
}
deinit {
self.context?.targetRemoved(id: self.id)
}
}
public final class TargetState {
var currentFrameExpirationTimestamp: Double?
init() {
}
}
private final class ReadingContext {
let dataPath: String
var isFailed: Bool = false
var reader: FFMpegFileReader?
init(dataPath: String) {
self.dataPath = dataPath
}
func advance() -> CMSampleBuffer? {
outer: while true {
if self.isFailed {
break outer
}
if self.reader == nil {
let reader = FFMpegFileReader(
source: .file(self.dataPath),
useHardwareAcceleration: false,
selectedStream: .mediaType(.video),
seek: nil,
maxReadablePts: nil
)
if reader == nil {
self.isFailed = true
break outer
}
self.reader = reader
}
guard let reader = self.reader else {
break outer
}
switch reader.readFrame() {
case let .frame(frame):
return createSampleBuffer(fromSampleBuffer: frame.sampleBuffer, withTimeOffset: .zero, duration: nil, displayImmediately: true)
case .error:
self.isFailed = true
break outer
case .endOfStream:
self.reader = nil
case .waitingForMoreData:
self.isFailed = true
break outer
}
}
return nil
}
}
private final class TargetContext {
weak var target: Target?
let file: TelegramMediaFile
let userLocation: MediaResourceUserLocation
var readingContext: QueueLocalObject<ReadingContext>?
var fetchDisposable: Disposable?
var dataDisposable: Disposable?
var dataPath: String?
init(
target: Target,
file: TelegramMediaFile,
userLocation: MediaResourceUserLocation
) {
self.target = target
self.file = file
self.userLocation = userLocation
}
deinit {
self.fetchDisposable?.dispose()
self.dataDisposable?.dispose()
}
}
private static let sharedQueue = Queue(name: "BatchVideoRenderingContext", qos: .default)
private let context: AccountContext
private var targetContexts: [Int: TargetContext] = [:]
private var nextId: Int = 0
private var isRendering: Bool = false
private var displayLink: SharedDisplayLinkDriver.Link?
public init(context: AccountContext) {
self.context = context
}
public func add(target: Target, file: TelegramMediaFile, userLocation: MediaResourceUserLocation) -> TargetHandle {
let id = self.nextId
self.nextId += 1
self.targetContexts[id] = TargetContext(
target: target,
file: file,
userLocation: userLocation
)
self.update()
return TargetHandle(context: self, id: id)
}
private func targetRemoved(id: Int) {
if self.targetContexts.removeValue(forKey: id) != nil {
self.update()
}
}
private func update() {
var removeIds: [Int] = []
for (id, targetContext) in self.targetContexts {
if targetContext.target != nil {
if targetContext.fetchDisposable == nil {
//TODO:release pass resource reference
targetContext.fetchDisposable = fetchedMediaResource(
mediaBox: self.context.account.postbox.mediaBox,
userLocation: targetContext.userLocation,
userContentType: .sticker,
reference: .media(media: .standalone(media: targetContext.file), resource: targetContext.file.resource)
).startStrict()
}
if targetContext.dataDisposable == nil {
targetContext.dataDisposable = (self.context.account.postbox.mediaBox.resourceData(targetContext.file.resource)
|> deliverOnMainQueue).startStrict(next: { [weak self, weak targetContext] data in
guard let self, let targetContext else {
return
}
if data.complete && targetContext.dataPath == nil {
targetContext.dataPath = data.path
self.update()
}
})
}
if targetContext.readingContext == nil, let dataPath = targetContext.dataPath {
targetContext.readingContext = QueueLocalObject(queue: BatchVideoRenderingContext.sharedQueue, generate: {
return ReadingContext(dataPath: dataPath)
})
}
} else {
removeIds.append(id)
}
}
for id in removeIds {
self.targetContexts.removeValue(forKey: id)
}
if !self.targetContexts.isEmpty {
if self.displayLink == nil {
self.displayLink = SharedDisplayLinkDriver.shared.add { [weak self] _ in
guard let self else {
return
}
self.updateRendering()
}
}
} else {
self.displayLink = nil
}
}
private func updateRendering() {
if self.isRendering {
return
}
let timestamp = CACurrentMediaTime()
var removeIds: [Int] = []
var renderIds: [Int] = []
for (id, targetContext) in self.targetContexts {
guard let target = targetContext.target else {
removeIds.append(id)
continue
}
let targetState: TargetState
if let current = target.batchVideoRenderingTargetState {
targetState = current
} else {
targetState = TargetState()
target.batchVideoRenderingTargetState = targetState
}
if let currentFrameExpirationTimestamp = targetState.currentFrameExpirationTimestamp {
if timestamp >= currentFrameExpirationTimestamp {
renderIds.append(id)
}
} else {
renderIds.append(id)
}
}
for id in removeIds {
self.targetContexts.removeValue(forKey: id)
}
if !renderIds.isEmpty {
self.isRendering = true
var readingContexts: [Int: QueueLocalObject<ReadingContext>] = [:]
for id in renderIds {
guard let targetContext = self.targetContexts[id] else {
continue
}
if let readingContext = targetContext.readingContext {
readingContexts[id] = readingContext
}
}
BatchVideoRenderingContext.sharedQueue.async { [weak self] in
var sampleBuffers: [Int: CMSampleBuffer?] = [:]
for (id, readingContext) in readingContexts {
guard let readingContext = readingContext.unsafeGet() else {
sampleBuffers[id] = nil
continue
}
if let sampleBuffer = readingContext.advance() {
sampleBuffers[id] = sampleBuffer
} else {
sampleBuffers[id] = nil
}
}
Queue.mainQueue().async {
guard let self else {
return
}
self.isRendering = false
for (id, sampleBuffer) in sampleBuffers {
guard let targetContext = self.targetContexts[id], let target = targetContext.target, let targetState = target.batchVideoRenderingTargetState else {
return
}
if let sampleBuffer {
target.setSampleBuffer(sampleBuffer: sampleBuffer)
if let targetState = target.batchVideoRenderingTargetState {
targetState.currentFrameExpirationTimestamp = CACurrentMediaTime() + CMSampleBufferGetDuration(sampleBuffer).seconds
}
} else {
targetState.currentFrameExpirationTimestamp = CACurrentMediaTime() + 1.0 / 30.0
}
}
}
}
}
if !self.targetContexts.isEmpty {
if self.displayLink == nil {
self.displayLink = SharedDisplayLinkDriver.shared.add { [weak self] _ in
guard let self else {
return
}
self.updateRendering()
}
}
} else {
self.displayLink = nil
}
}
}
private func createSampleBuffer(fromSampleBuffer sampleBuffer: CMSampleBuffer, withTimeOffset timeOffset: CMTime, duration: CMTime?, displayImmediately: Bool) -> CMSampleBuffer? {
var itemCount: CMItemCount = 0
var status = CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: 0, arrayToFill: nil, entriesNeededOut: &itemCount)
if status != 0 {
return nil
}
var timingInfo = [CMSampleTimingInfo](repeating: CMSampleTimingInfo(duration: CMTimeMake(value: 0, timescale: 0), presentationTimeStamp: CMTimeMake(value: 0, timescale: 0), decodeTimeStamp: CMTimeMake(value: 0, timescale: 0)), count: itemCount)
status = CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: itemCount, arrayToFill: &timingInfo, entriesNeededOut: &itemCount)
if status != 0 {
return nil
}
if let dur = duration {
for i in 0 ..< itemCount {
timingInfo[i].decodeTimeStamp = CMTimeAdd(timingInfo[i].decodeTimeStamp, timeOffset)
timingInfo[i].presentationTimeStamp = CMTimeAdd(timingInfo[i].presentationTimeStamp, timeOffset)
timingInfo[i].duration = dur
}
} else {
for i in 0 ..< itemCount {
timingInfo[i].decodeTimeStamp = CMTimeAdd(timingInfo[i].decodeTimeStamp, timeOffset)
timingInfo[i].presentationTimeStamp = CMTimeAdd(timingInfo[i].presentationTimeStamp, timeOffset)
}
}
var sampleBufferOffset: CMSampleBuffer?
CMSampleBufferCreateCopyWithNewTiming(allocator: kCFAllocatorDefault, sampleBuffer: sampleBuffer, sampleTimingEntryCount: itemCount, sampleTimingArray: &timingInfo, sampleBufferOut: &sampleBufferOffset)
guard let sampleBufferOffset else {
return nil
}
if displayImmediately {
let attachments: NSArray = CMSampleBufferGetSampleAttachmentsArray(sampleBufferOffset, createIfNecessary: true)! as NSArray
let dict: NSMutableDictionary = attachments[0] as! NSMutableDictionary
dict[kCMSampleAttachmentKey_DisplayImmediately as NSString] = true as NSNumber
}
return sampleBufferOffset
}

View File

@ -530,6 +530,11 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
private var appliedHlsInlinePlaybackRange: Range<Int64>?
private var hlsInlinePlaybackRangeDisposable: Disposable?
#if DEBUG && false
private var testDeferHLSMedia: Bool = true
private var deferHLSMediaTimer: Foundation.Timer?
#endif
override public init() {
self.pinchContainerNode = PinchSourceContainerNode()
@ -864,9 +869,36 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
let hlsInlinePlaybackRange = self.hlsInlinePlaybackRange
let appliedHlsInlinePlaybackRange = self.appliedHlsInlinePlaybackRange
#if DEBUG && false
let testDeferHLSMedia = self.testDeferHLSMedia
#endif
return { [weak self] context, presentationData, dateTimeFormat, message, associatedData, attributes, media, mediaIndex, dateAndStatus, automaticDownload, peerType, peerId, sizeCalculation, layoutConstants, contentMode, presentationContext in
let _ = peerType
#if DEBUG && false
var media = media
var maybeRestoreHLSMedia = false
if testDeferHLSMedia {
if let file = media as? TelegramMediaFile, !file.alternativeRepresentations.isEmpty {
maybeRestoreHLSMedia = true
media = TelegramMediaFile(
fileId: file.fileId,
partialReference: file.partialReference,
resource: file.resource,
previewRepresentations: file.previewRepresentations,
videoThumbnails: file.videoThumbnails,
videoCover: file.videoCover,
immediateThumbnailData: file.immediateThumbnailData,
mimeType: file.mimeType,
size: file.size,
attributes: file.attributes,
alternativeRepresentations: []
)
}
}
#endif
var useInlineHLS = true
var displayInlineScrubber = true
var startFromSavedPosition = true
@ -882,13 +914,6 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
}
}
/*#if DEBUG
if "".isEmpty {
displayInlineScrubber = false
startFromSavedPosition = false
}
#endif*/
var nativeSize: CGSize
let isSecretMedia = message.containsSecretMedia
@ -1822,6 +1847,18 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
strongSelf.automaticDownload = automaticDownload
strongSelf.preferredStoryHighQuality = associatedData.preferredStoryHighQuality
strongSelf.showSensitiveContent = associatedData.showSensitiveContent
#if DEBUG && false
if strongSelf.testDeferHLSMedia && maybeRestoreHLSMedia && strongSelf.deferHLSMediaTimer == nil {
strongSelf.deferHLSMediaTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false, block: { [weak strongSelf] _ in
guard let strongSelf else {
return
}
strongSelf.testDeferHLSMedia = false
strongSelf.requestInlineUpdate?()
})
}
#endif
if let previousArguments = strongSelf.currentImageArguments {
if previousArguments.imageSize == arguments.imageSize {

View File

@ -50,6 +50,7 @@ swift_library(
"//submodules/TelegramUIPreferences",
"//submodules/TelegramCore/FlatBuffers",
"//submodules/TelegramCore/FlatSerialization",
"//submodules/TelegramUI/Components/BatchVideoRendering",
],
visibility = [
"//visibility:public",

View File

@ -19,18 +19,20 @@ import SoftwareVideo
import AVFoundation
import PhotoResources
import ShimmerEffect
import BatchVideoRendering
private class GifVideoLayer: AVSampleBufferDisplayLayer {
private class GifVideoLayer: AVSampleBufferDisplayLayer, BatchVideoRenderingContext.Target {
private let context: AccountContext
private let batchVideoContext: BatchVideoRenderingContext
private let userLocation: MediaResourceUserLocation
private let file: TelegramMediaFile?
private var frameManager: SoftwareVideoLayerFrameManager?
private var batchVideoTargetHandle: BatchVideoRenderingContext.TargetHandle?
var batchVideoRenderingTargetState: BatchVideoRenderingContext.TargetState?
private var thumbnailDisposable: Disposable?
private var playbackTimestamp: Double = 0.0
private var playbackTimer: SwiftSignalKit.Timer?
private var isReadyToRender: Bool = false
var started: (() -> Void)?
@ -39,28 +41,13 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer {
if self.shouldBeAnimating == oldValue {
return
}
if self.shouldBeAnimating {
self.playbackTimer?.invalidate()
let startTimestamp = self.playbackTimestamp + CFAbsoluteTimeGetCurrent()
self.playbackTimer = SwiftSignalKit.Timer(timeout: 1.0 / 30.0, repeat: true, completion: { [weak self] in
guard let strongSelf = self else {
return
}
let timestamp = CFAbsoluteTimeGetCurrent() - startTimestamp
strongSelf.frameManager?.tick(timestamp: timestamp)
strongSelf.playbackTimestamp = timestamp
}, queue: .mainQueue())
self.playbackTimer?.start()
} else {
self.playbackTimer?.invalidate()
self.playbackTimer = nil
}
self.updateShouldBeRendering()
}
}
init(context: AccountContext, userLocation: MediaResourceUserLocation, file: TelegramMediaFile?, synchronousLoad: Bool) {
init(context: AccountContext, batchVideoContext: BatchVideoRenderingContext, userLocation: MediaResourceUserLocation, file: TelegramMediaFile?, synchronousLoad: Bool) {
self.context = context
self.batchVideoContext = batchVideoContext
self.userLocation = userLocation
self.file = file
@ -102,6 +89,7 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer {
}
self.context = layer.context
self.batchVideoContext = layer.batchVideoContext
self.userLocation = layer.userLocation
self.file = layer.file
@ -117,18 +105,28 @@ private class GifVideoLayer: AVSampleBufferDisplayLayer {
}
private func setupVideo() {
guard let file = self.file else {
return
}
let frameManager = SoftwareVideoLayerFrameManager(account: self.context.account, userLocation: self.userLocation, userContentType: .other, fileReference: .savedGif(media: file), layerHolder: nil, layer: self)
self.frameManager = frameManager
frameManager.started = { [weak self] in
guard let strongSelf = self else {
return
self.isReadyToRender = true
self.updateShouldBeRendering()
}
private func updateShouldBeRendering() {
let shouldBeRendering = self.shouldBeAnimating && self.isReadyToRender
if shouldBeRendering, let file = self.file {
if self.batchVideoTargetHandle == nil {
self.batchVideoTargetHandle = self.batchVideoContext.add(target: self, file: file, userLocation: self.userLocation)
}
let _ = strongSelf
} else {
self.batchVideoTargetHandle = nil
}
}
func setSampleBuffer(sampleBuffer: CMSampleBuffer) {
if #available(iOS 17.0, *) {
self.sampleBufferRenderer.enqueue(sampleBuffer)
} else {
self.enqueue(sampleBuffer)
}
frameManager.start()
}
}
@ -382,6 +380,7 @@ public final class GifPagerContentComponent: Component {
init(
item: Item?,
context: AccountContext,
batchVideoContext: BatchVideoRenderingContext,
groupId: String,
attemptSynchronousLoad: Bool,
onUpdateDisplayPlaceholder: @escaping (Bool, Double) -> Void
@ -389,7 +388,7 @@ public final class GifPagerContentComponent: Component {
self.item = item
self.onUpdateDisplayPlaceholder = onUpdateDisplayPlaceholder
super.init(context: context, userLocation: .other, file: item?.file.media, synchronousLoad: attemptSynchronousLoad)
super.init(context: context, batchVideoContext: batchVideoContext, userLocation: .other, file: item?.file.media, synchronousLoad: attemptSynchronousLoad)
if item == nil {
self.updateDisplayPlaceholder(displayPlaceholder: true, duration: 0.0)
@ -594,6 +593,7 @@ public final class GifPagerContentComponent: Component {
private var pagerEnvironment: PagerComponentChildEnvironment?
private var theme: PresentationTheme?
private var itemLayout: ItemLayout?
private var batchVideoContext: BatchVideoRenderingContext?
private var currentLoadMoreToken: String?
@ -833,6 +833,14 @@ public final class GifPagerContentComponent: Component {
searchInset += itemLayout.searchHeight
}
let batchVideoContext: BatchVideoRenderingContext
if let current = self.batchVideoContext {
batchVideoContext = current
} else {
batchVideoContext = BatchVideoRenderingContext(context: component.context)
self.batchVideoContext = batchVideoContext
}
if let itemRange = itemLayout.visibleItems(for: self.scrollView.bounds) {
for index in itemRange.lowerBound ..< itemRange.upperBound {
var item: Item?
@ -869,6 +877,7 @@ public final class GifPagerContentComponent: Component {
itemLayer = ItemLayer(
item: item,
context: component.context,
batchVideoContext: batchVideoContext,
groupId: "savedGif",
attemptSynchronousLoad: attemptSynchronousLoads,
onUpdateDisplayPlaceholder: { [weak self] displayPlaceholder, duration in

View File

@ -118,21 +118,6 @@ final class GalleryHiddenMediaManagerImpl: GalleryHiddenMediaManager {
}))
return index
/*let index = self.sourcesDisposables.add((signal |> deliverOnMainQueue).start(next: { [weak self] id in
if let strongSelf = self {
if id != state?.0 {
if let (previousId, previousIndex) = state {
strongSelf.removeHiddenMedia(id: previousId, index: previousIndex)
state = nil
}
if let id = id {
state = (id, strongSelf.addHiddenMedia(id: id))
}
}
}
}))
return index*/
}
func removeSource(_ index: Int) {

View File

@ -58,6 +58,8 @@ public final class MediaManagerImpl: NSObject, MediaManager {
}
}
public weak var currentPictureInPictureNode: AnyObject?
private let queue = Queue.mainQueue()
private let accountManager: AccountManager<TelegramAccountManagerTypes>

View File

@ -318,6 +318,11 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool {
})
case let .gallery(gallery):
params.dismissInput()
if GalleryController.maybeExpandPIP(context: params.context, messageId: params.message.id) {
return true
}
let _ = (gallery
|> deliverOnMainQueue).startStandalone(next: { gallery in
gallery.centralItemUpdated = { messageId in

View File

@ -1105,7 +1105,7 @@ final class HLSVideoJSNativeContentNode: ASDisplayNode, UniversalVideoContentNod
let thumbnailVideoReference = HLSVideoContent.minimizedHLSQuality(file: fileReference, codecConfiguration: self.codecConfiguration)?.file ?? fileReference
self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: thumbnailVideoReference, previewSourceFileReference: nil, imageReference: nil, onlyFullSize: onlyFullSizeThumbnail, useLargeThumbnail: useLargeThumbnail, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail || fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in
self.imageNode.setSignal(internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: thumbnailVideoReference, previewSourceFileReference: fileReference, imageReference: nil, onlyFullSize: onlyFullSizeThumbnail, useLargeThumbnail: useLargeThumbnail, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail || fileReference.media.isInstantVideo) |> map { [weak self] getSize, getData in
Queue.mainQueue().async {
if let strongSelf = self, strongSelf.dimensions == nil {
if let dimensions = getSize() {

View File

@ -678,8 +678,11 @@ private:
- (void)setTone:(CallAudioTone * _Nullable)tone {
_audioDeviceModule->perform([tone](tgcalls::SharedAudioDeviceModule *audioDeviceModule) {
//audioDeviceModule->audioDeviceModule()->setTone([tone asTone]);
//TODO:implement
#ifdef WEBRTC_IOS
WrappedAudioDeviceModuleIOS *deviceModule = (WrappedAudioDeviceModuleIOS *)audioDeviceModule->audioDeviceModule().get();
webrtc::tgcalls_ios_adm::AudioDeviceModuleIOS *deviceModule_iOS = (webrtc::tgcalls_ios_adm::AudioDeviceModuleIOS *)deviceModule->WrappedInstance().get();
deviceModule_iOS->setTone([tone asTone]);
#endif
});
}

@ -1 +1 @@
Subproject commit b07cb07fb9bcb97f745e74c27f8751e8bef1dfb3
Subproject commit d50eeeb40ce6a2d36d505bcaf0b5f4e5ed473f22