mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 00:21:12 +00:00
Added recent stickers clearing Added sending logs via email Added forward recipient change on forward acccessory panel tap Tweaked undo panel design Various UI fixes
161 lines
6.4 KiB
Swift
161 lines
6.4 KiB
Swift
import Foundation
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import Postbox
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
|
|
private struct FetchControls {
|
|
let fetch: (Bool) -> Void
|
|
let cancel: () -> Void
|
|
}
|
|
|
|
final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode {
|
|
private let context: AccountContext
|
|
let media: InstantPageMedia
|
|
private let interactive: Bool
|
|
private let openMedia: (InstantPageMedia) -> Void
|
|
private var fetchControls: FetchControls?
|
|
|
|
private let videoNode: UniversalVideoNode
|
|
private let statusNode: RadialStatusNode
|
|
|
|
private var currentSize: CGSize?
|
|
|
|
private var fetchStatus: MediaResourceStatus?
|
|
private var fetchedDisposable = MetaDisposable()
|
|
private var statusDisposable = MetaDisposable()
|
|
|
|
private var localIsVisible = false
|
|
|
|
init(context: AccountContext, webPage: TelegramMediaWebpage, theme: InstantPageTheme, media: InstantPageMedia, interactive: Bool, openMedia: @escaping (InstantPageMedia) -> Void) {
|
|
self.context = context
|
|
self.media = media
|
|
self.interactive = interactive
|
|
self.openMedia = openMedia
|
|
|
|
var imageReference: ImageMediaReference?
|
|
if let file = media.media as? TelegramMediaFile, let presentation = smallestImageRepresentation(file.previewRepresentations) {
|
|
let image = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [presentation], immediateThumbnailData: nil, reference: nil, partialReference: nil)
|
|
imageReference = ImageMediaReference.webPage(webPage: WebpageReference(webPage), media: image)
|
|
}
|
|
|
|
var streamVideo = false
|
|
if let file = media.media as? TelegramMediaFile {
|
|
streamVideo = isMediaStreamable(media: file)
|
|
}
|
|
|
|
self.videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: context.sharedContext.mediaManager.audioSession, manager: context.sharedContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: NativeVideoContent(id: .instantPage(webPage.webpageId, media.media.id!), fileReference: .webPage(webPage: WebpageReference(webPage), media: media.media as! TelegramMediaFile), imageReference: imageReference, streamVideo: streamVideo ? .conservative : .none, loopVideo: true, enableSound: false, fetchAutomatically: true, placeholderColor: theme.pageBackgroundColor), priority: .embedded, autoplay: true)
|
|
self.videoNode.isUserInteractionEnabled = false
|
|
|
|
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
|
|
|
|
super.init()
|
|
|
|
self.addSubnode(self.videoNode)
|
|
|
|
if let file = media.media as? TelegramMediaFile {
|
|
self.fetchedDisposable.set(fetchedMediaResource(postbox: context.account.postbox, reference: AnyMediaReference.webPage(webPage: WebpageReference(webPage), media: file).resourceReference(file.resource)).start())
|
|
|
|
self.statusDisposable.set((context.account.postbox.mediaBox.resourceStatus(file.resource) |> deliverOnMainQueue).start(next: { [weak self] status in
|
|
displayLinkDispatcher.dispatch {
|
|
if let strongSelf = self {
|
|
strongSelf.fetchStatus = status
|
|
strongSelf.updateFetchStatus()
|
|
}
|
|
}
|
|
}))
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
self.fetchedDisposable.dispose()
|
|
}
|
|
|
|
override func didLoad() {
|
|
super.didLoad()
|
|
|
|
if self.interactive {
|
|
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
|
}
|
|
}
|
|
|
|
func updateIsVisible(_ isVisible: Bool) {
|
|
if self.localIsVisible != isVisible {
|
|
self.localIsVisible = isVisible
|
|
|
|
self.videoNode.canAttachContent = isVisible
|
|
}
|
|
}
|
|
|
|
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
|
}
|
|
|
|
func update(strings: PresentationStrings, theme: InstantPageTheme) {
|
|
}
|
|
|
|
private func updateFetchStatus() {
|
|
var state: RadialStatusNodeState = .none
|
|
if let fetchStatus = self.fetchStatus {
|
|
switch fetchStatus {
|
|
case let .Fetching(_, progress):
|
|
let adjustedProgress = max(progress, 0.027)
|
|
state = .progress(color: .white, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: true)
|
|
case .Remote:
|
|
state = .download(.white)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
self.statusNode.transitionToState(state, completion: { [weak statusNode] in
|
|
if state == .none {
|
|
statusNode?.removeFromSupernode()
|
|
}
|
|
})
|
|
}
|
|
|
|
override func layout() {
|
|
super.layout()
|
|
|
|
let size = self.bounds.size
|
|
|
|
if self.currentSize != size {
|
|
self.currentSize = size
|
|
|
|
self.videoNode.frame = CGRect(origin: CGPoint(), size: size)
|
|
self.videoNode.updateLayout(size: size, transition: .immediate)
|
|
|
|
let radialStatusSize: CGFloat = 50.0
|
|
self.statusNode.frame = CGRect(x: floorToScreenPixels((size.width - radialStatusSize) / 2.0), y: floorToScreenPixels((size.height - radialStatusSize) / 2.0), width: radialStatusSize, height: radialStatusSize)
|
|
}
|
|
}
|
|
|
|
func transitionNode(media: InstantPageMedia) -> (ASDisplayNode, () -> (UIView?, UIView?))? {
|
|
if media == self.media {
|
|
let videoNode = self.videoNode
|
|
return (self.videoNode, { [weak videoNode] in
|
|
return (videoNode?.view.snapshotContentTree(unhide: true), nil)
|
|
})
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func updateHiddenMedia(media: InstantPageMedia?) {
|
|
self.videoNode.isHidden = self.media == media
|
|
}
|
|
|
|
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
|
if case .ended = recognizer.state, let fetchStatus = self.fetchStatus {
|
|
switch fetchStatus {
|
|
case .Local:
|
|
self.openMedia(self.media)
|
|
case .Remote:
|
|
self.fetchControls?.fetch(true)
|
|
case .Fetching:
|
|
self.fetchControls?.cancel()
|
|
}
|
|
}
|
|
}
|
|
}
|