import Foundation import UIKit import AsyncDisplayKit import SwiftSignalKit import Display import TelegramCore import SyncCore import Postbox import TelegramAudio import AccountContext public final class OverlayUniversalVideoNode: OverlayMediaItemNode { public let content: UniversalVideoContent private let videoNode: UniversalVideoNode private let decoration: OverlayVideoDecoration private var validLayoutSize: CGSize? private var shouldBeDismissedDisposable: Disposable? override public var group: OverlayMediaItemNodeGroup? { return OverlayMediaItemNodeGroup(rawValue: 0) } override public var isMinimizeable: Bool { return true } public var canAttachContent: Bool = true { didSet { self.videoNode.canAttachContent = self.canAttachContent } } private let defaultExpand: () -> Void public var customExpand: (() -> Void)? public var customClose: (() -> Void)? public var controlsAreShowingUpdated: ((Bool) -> Void)? public init(postbox: Postbox, audioSession: ManagedAudioSession, manager: UniversalVideoManager, content: UniversalVideoContent, shouldBeDismissed: Signal = .single(false), expand: @escaping () -> Void, close: @escaping () -> Void) { self.content = content self.defaultExpand = expand var expandImpl: (() -> Void)? var controlsAreShowingUpdatedImpl: ((Bool) -> Void)? var unminimizeImpl: (() -> Void)? var togglePlayPauseImpl: (() -> Void)? var closeImpl: (() -> Void)? let decoration = OverlayVideoDecoration(contentDimensions: content.dimensions, unminimize: { unminimizeImpl?() }, togglePlayPause: { togglePlayPauseImpl?() }, expand: { expandImpl?() }, close: { closeImpl?() }, controlsAreShowingUpdated: { value in controlsAreShowingUpdatedImpl?(value) }) self.videoNode = UniversalVideoNode(postbox: postbox, audioSession: audioSession, manager: manager, decoration: decoration, content: content, priority: .overlay) self.decoration = decoration super.init() expandImpl = { [weak self] in self?.expand() } unminimizeImpl = { [weak self] in self?.unminimize?() } togglePlayPauseImpl = { [weak self] in self?.videoNode.togglePlayPause() } closeImpl = { [weak self] in if let strongSelf = self { if let customClose = strongSelf.customClose { customClose() return } if strongSelf.videoNode.hasAttachedContext { strongSelf.videoNode.continuePlayingWithoutSound() } strongSelf.layer.animateScale(from: 1.0, to: 0.1, duration: 0.25, removeOnCompletion: false, completion: { _ in self?.dismiss() close() }) strongSelf.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false) } } controlsAreShowingUpdatedImpl = { [weak self] value in self?.controlsAreShowingUpdated?(value) } self.clipsToBounds = true self.cornerRadius = 4.0 self.addSubnode(self.videoNode) self.videoNode.ownsContentNodeUpdated = { [weak self] value in if let strongSelf = self { let previous = strongSelf.hasAttachedContext strongSelf.hasAttachedContext = value strongSelf.hasAttachedContextUpdated?(value) if previous != value { if !value { strongSelf.dismiss() closeImpl?() } } } } self.videoNode.canAttachContent = true self.shouldBeDismissedDisposable = (shouldBeDismissed |> filter { $0 } |> deliverOnMainQueue).start(next: { [weak self] _ in guard let strongSelf = self else { return } strongSelf.dismiss() closeImpl?() }) } override public func didLoad() { super.didLoad() } override public func layout() { self.updateLayout(self.bounds.size) } override public func preferredSizeForOverlayDisplay(boundingSize: CGSize) -> CGSize { return self.content.dimensions.aspectFitted(CGSize(width: 300.0, height: 300.0)) } override public func updateLayout(_ size: CGSize) { if size != self.validLayoutSize { self.updateLayoutImpl(size, transition: .immediate) } } public func updateLayout(_ size: CGSize, transition: ContainedViewLayoutTransition) { if size != self.validLayoutSize { self.updateLayoutImpl(size, transition: transition) } } private func updateLayoutImpl(_ size: CGSize, transition: ContainedViewLayoutTransition) { self.validLayoutSize = size transition.updateFrame(node: self.videoNode, frame: CGRect(origin: CGPoint(), size: size)) self.videoNode.updateLayout(size: size, transition: transition) } override public func updateMinimizedEdge(_ edge: OverlayMediaItemMinimizationEdge?, adjusting: Bool) { self.decoration.updateMinimizedEdge(edge, adjusting: adjusting) } public func updateRoundCorners(_ value: Bool, transition: ContainedViewLayoutTransition) { transition.updateCornerRadius(node: self, cornerRadius: value ? 4.0 : 0.0) } public func showControls() { self.decoration.showControls() } public func expand() { if let customExpand = self.customExpand { customExpand() } else { self.defaultExpand() } } public func controlPlay() { self.videoNode.play() } }