mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
c39fdb4463
2
.gitignore
vendored
2
.gitignore
vendored
@ -68,4 +68,4 @@ build-input/*
|
||||
submodules/OpusBinding/SharedHeaders/*
|
||||
submodules/FFMpegBinding/SharedHeaders/*
|
||||
submodules/OpenSSLEncryptionProvider/SharedHeaders/*
|
||||
|
||||
buildServer.json
|
||||
|
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal 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
5
.vscode/settings.json
vendored
Normal 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
19
.vscode/tasks.json
vendored
Normal 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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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 }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
|
@ -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 }
|
||||
|
@ -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)))
|
||||
|
||||
|
@ -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)))
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
@ -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);
|
||||
}
|
23
submodules/TelegramCore/FlatSerialization/Models/Media.fbs
Normal file
23
submodules/TelegramCore/FlatSerialization/Models/Media.fbs
Normal 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;
|
@ -0,0 +1,5 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
struct OptionalBool {
|
||||
value:bool (id: 0);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
table PeerNameColor {
|
||||
value:int32 (id: 0);
|
||||
}
|
||||
|
||||
root_type PeerNameColor;
|
@ -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);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
table StarsAmount {
|
||||
value:int64 (id: 0);
|
||||
nanos:int32 (id: 1);
|
||||
}
|
@ -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;
|
@ -0,0 +1,7 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
table TelegramChatAdminRights {
|
||||
rights:int32 (id: 0);
|
||||
}
|
||||
|
||||
root_type TelegramChatAdminRights;
|
@ -0,0 +1,7 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
table TelegramChatBannedRights {
|
||||
flags:int32 (id: 0);
|
||||
untilDate:int32 (id: 1);
|
||||
}
|
||||
|
@ -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;
|
@ -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);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace TelegramCore;
|
||||
|
||||
table TelegramPeerUsername {
|
||||
flags:int32 (id: 0);
|
||||
username:string (id: 1, required);
|
||||
}
|
||||
|
||||
root_type TelegramPeerUsername;
|
@ -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;
|
@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
|
||||
|
||||
public enum TelegramChannelPermission {
|
||||
case sendText
|
||||
case sendPhoto
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)))))
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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) }))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
54
submodules/TelegramCore/Sources/Utils/FlatBuffersUtils.swift
Normal file
54
submodules/TelegramCore/Sources/Utils/FlatBuffersUtils.swift
Normal 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)
|
||||
}
|
||||
}
|
22
submodules/TelegramUI/Components/BatchVideoRendering/BUILD
Normal file
22
submodules/TelegramUI/Components/BatchVideoRendering/BUILD
Normal 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",
|
||||
],
|
||||
)
|
@ -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
|
||||
}
|
@ -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 {
|
||||
|
@ -50,6 +50,7 @@ swift_library(
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/TelegramCore/FlatBuffers",
|
||||
"//submodules/TelegramCore/FlatSerialization",
|
||||
"//submodules/TelegramUI/Components/BatchVideoRendering",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user