mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-31 01:42:18 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
a68bf9bcae
1
.bazelrc
1
.bazelrc
@ -29,7 +29,6 @@ build --features=debug_prefix_map_pwd_is_dot
|
||||
build --features=swift.cacheable_swiftmodules
|
||||
build --features=swift.debug_prefix_map
|
||||
build --features=swift.enable_vfsoverlays
|
||||
build --features=swift.vfsoverlay
|
||||
|
||||
build --strategy=Genrule=standalone
|
||||
build --spawn_strategy=standalone
|
||||
|
@ -20,7 +20,7 @@ public protocol UniversalVideoContentNode: AnyObject {
|
||||
var status: Signal<MediaPlayerStatus, NoError> { get }
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> { get }
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition)
|
||||
|
||||
func play()
|
||||
func pause()
|
||||
@ -68,7 +68,7 @@ public protocol UniversalVideoDecoration: AnyObject {
|
||||
|
||||
func updateContentNode(_ contentNode: (UniversalVideoContentNode & ASDisplayNode)?)
|
||||
func updateContentNodeSnapshot(_ snapshot: UIView?)
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition)
|
||||
func tap()
|
||||
}
|
||||
|
||||
@ -247,8 +247,8 @@ public final class UniversalVideoNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.decoration.updateLayout(size: size, transition: transition)
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize? = nil, transition: ContainedViewLayoutTransition) {
|
||||
self.decoration.updateLayout(size: size, actualSize: actualSize ?? size, transition: transition)
|
||||
}
|
||||
|
||||
public func play() {
|
||||
|
@ -325,7 +325,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -345,9 +345,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -405,8 +405,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -421,7 +421,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -1161,9 +1161,9 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1221,8 +1221,8 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -1237,7 +1237,7 @@ private final class StickerVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -34,9 +34,9 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +94,8 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -110,7 +110,7 @@ public final class GalleryVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1186,7 +1186,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
||||
videoScale = 2.0
|
||||
}
|
||||
let videoSize = CGSize(width: item.content.dimensions.width * videoScale, height: item.content.dimensions.height * videoScale)
|
||||
videoNode.updateLayout(size: videoSize, transition: .immediate)
|
||||
let actualVideoSize = CGSize(width: item.content.dimensions.width, height: item.content.dimensions.height)
|
||||
videoNode.updateLayout(size: videoSize, actualSize: actualVideoSize, transition: .immediate)
|
||||
videoNode.ownsContentNodeUpdated = { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateDisplayPlaceholder(!value)
|
||||
|
@ -626,7 +626,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -646,9 +646,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -706,8 +706,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -722,7 +722,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -511,7 +511,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -531,9 +531,9 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -591,8 +591,8 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -607,7 +607,7 @@ private final class VideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,13 +112,14 @@ private final class InteractiveTextNodeLine {
|
||||
let isTruncated: Bool
|
||||
let isRTL: Bool
|
||||
var strikethroughs: [InteractiveTextNodeStrikethrough]
|
||||
var underlines: [InteractiveTextNodeStrikethrough]
|
||||
var spoilers: [InteractiveTextNodeSpoiler]
|
||||
var spoilerWords: [InteractiveTextNodeSpoiler]
|
||||
var embeddedItems: [InteractiveTextNodeEmbeddedItem]
|
||||
var attachments: [InteractiveTextNodeAttachment]
|
||||
let additionalTrailingLine: (CTLine, Double)?
|
||||
|
||||
init(line: CTLine, constrainedWidth: CGFloat, frame: CGRect, intrinsicWidth: CGFloat, ascent: CGFloat, descent: CGFloat, range: NSRange?, isTruncated: Bool, isRTL: Bool, strikethroughs: [InteractiveTextNodeStrikethrough], spoilers: [InteractiveTextNodeSpoiler], spoilerWords: [InteractiveTextNodeSpoiler], embeddedItems: [InteractiveTextNodeEmbeddedItem], attachments: [InteractiveTextNodeAttachment], additionalTrailingLine: (CTLine, Double)?) {
|
||||
init(line: CTLine, constrainedWidth: CGFloat, frame: CGRect, intrinsicWidth: CGFloat, ascent: CGFloat, descent: CGFloat, range: NSRange?, isTruncated: Bool, isRTL: Bool, strikethroughs: [InteractiveTextNodeStrikethrough], underlines: [InteractiveTextNodeStrikethrough], spoilers: [InteractiveTextNodeSpoiler], spoilerWords: [InteractiveTextNodeSpoiler], embeddedItems: [InteractiveTextNodeEmbeddedItem], attachments: [InteractiveTextNodeAttachment], additionalTrailingLine: (CTLine, Double)?) {
|
||||
self.line = line
|
||||
self.constrainedWidth = constrainedWidth
|
||||
self.frame = frame
|
||||
@ -129,6 +130,7 @@ private final class InteractiveTextNodeLine {
|
||||
self.isTruncated = isTruncated
|
||||
self.isRTL = isRTL
|
||||
self.strikethroughs = strikethroughs
|
||||
self.underlines = underlines
|
||||
self.spoilers = spoilers
|
||||
self.spoilerWords = spoilerWords
|
||||
self.embeddedItems = embeddedItems
|
||||
@ -1452,6 +1454,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
isTruncated: false,
|
||||
isRTL: false,
|
||||
strikethroughs: [],
|
||||
underlines: [],
|
||||
spoilers: [],
|
||||
spoilerWords: [],
|
||||
embeddedItems: [],
|
||||
@ -1493,6 +1496,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
isTruncated: false,
|
||||
isRTL: isRTL && segment.blockQuote == nil,
|
||||
strikethroughs: [],
|
||||
underlines: [],
|
||||
spoilers: [],
|
||||
spoilerWords: [],
|
||||
embeddedItems: [],
|
||||
@ -1551,6 +1555,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
isTruncated: true,
|
||||
isRTL: lastLine.isRTL,
|
||||
strikethroughs: [],
|
||||
underlines: [],
|
||||
spoilers: [],
|
||||
spoilerWords: [],
|
||||
embeddedItems: [],
|
||||
@ -1605,6 +1610,7 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
isTruncated: true,
|
||||
isRTL: lastLine.isRTL,
|
||||
strikethroughs: [],
|
||||
underlines: [],
|
||||
spoilers: [],
|
||||
spoilerWords: [],
|
||||
embeddedItems: [],
|
||||
@ -1736,6 +1742,11 @@ open class InteractiveTextNode: ASDisplayNode, TextNodeProtocol, UIGestureRecogn
|
||||
let upperX = ceil(CTLineGetOffsetForStringIndex(line.line, range.location + range.length, nil))
|
||||
let x = lowerX < upperX ? lowerX : upperX
|
||||
line.strikethroughs.append(InteractiveTextNodeStrikethrough(range: range, frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: line.frame.height)))
|
||||
} else if let _ = attributes[NSAttributedString.Key.underlineStyle] {
|
||||
let lowerX = floor(CTLineGetOffsetForStringIndex(line.line, range.location, nil))
|
||||
let upperX = ceil(CTLineGetOffsetForStringIndex(line.line, range.location + range.length, nil))
|
||||
let x = lowerX < upperX ? lowerX : upperX
|
||||
line.underlines.append(InteractiveTextNodeStrikethrough(range: range, frame: CGRect(x: x, y: 0.0, width: abs(upperX - lowerX), height: line.frame.height)))
|
||||
}
|
||||
|
||||
if let embeddedItem = (attributes[NSAttributedString.Key(rawValue: "TelegramEmbeddedItem")] as? AnyHashable ?? attributes[NSAttributedString.Key(rawValue: "Attribute__EmbeddedItem")] as? AnyHashable) {
|
||||
@ -2090,6 +2101,14 @@ final class TextContentItem {
|
||||
}
|
||||
}
|
||||
|
||||
private let drawUnderlinesManually: Bool = {
|
||||
if #available(iOS 18.0, *) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}()
|
||||
|
||||
final class TextContentItemLayer: SimpleLayer {
|
||||
final class Params {
|
||||
let item: TextContentItem
|
||||
@ -2322,6 +2341,46 @@ final class TextContentItemLayer: SimpleLayer {
|
||||
}
|
||||
}
|
||||
|
||||
if drawUnderlinesManually {
|
||||
if !line.strikethroughs.isEmpty {
|
||||
for strikethrough in line.strikethroughs {
|
||||
guard let lineRange = line.range else {
|
||||
continue
|
||||
}
|
||||
var textColor: UIColor?
|
||||
params.item.attributedString?.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in
|
||||
if range == strikethrough.range, let color = attributes[NSAttributedString.Key.foregroundColor] as? UIColor {
|
||||
textColor = color
|
||||
}
|
||||
}
|
||||
if let textColor = textColor {
|
||||
context.setFillColor(textColor.cgColor)
|
||||
}
|
||||
let frame = strikethrough.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||
context.fill(CGRect(x: frame.minX, y: frame.midY, width: frame.width, height: 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
if !line.underlines.isEmpty {
|
||||
for strikethrough in line.underlines {
|
||||
guard let lineRange = line.range else {
|
||||
continue
|
||||
}
|
||||
var textColor: UIColor?
|
||||
params.item.attributedString?.enumerateAttributes(in: NSMakeRange(lineRange.location, lineRange.length), options: []) { attributes, range, _ in
|
||||
if range == strikethrough.range, let color = attributes[NSAttributedString.Key.foregroundColor] as? UIColor {
|
||||
textColor = color
|
||||
}
|
||||
}
|
||||
if let textColor = textColor {
|
||||
context.setFillColor(textColor.cgColor)
|
||||
}
|
||||
let frame = strikethrough.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||
context.fill(CGRect(x: frame.minX, y: frame.maxY - 2.0, width: frame.width, height: 1.0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let (additionalTrailingLine, _) = line.additionalTrailingLine {
|
||||
context.textPosition = CGPoint(x: lineFrame.minX + line.intrinsicWidth, y: lineFrame.maxY - line.descent)
|
||||
|
||||
|
@ -14,7 +14,7 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init() {
|
||||
self.contentContainerNode = ASDisplayNode()
|
||||
@ -34,9 +34,9 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,8 +94,8 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -110,7 +110,7 @@ public final class StoryVideoDecoration: UniversalVideoDecoration {
|
||||
}
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
171
submodules/TelegramUI/Resources/WebEmbed/HLSVideoPlayer.html
Executable file
171
submodules/TelegramUI/Resources/WebEmbed/HLSVideoPlayer.html
Executable file
@ -0,0 +1,171 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#videoPlayer {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: fill;
|
||||
}
|
||||
</style>
|
||||
<script src="hls.js"></script>
|
||||
<script type="text/javascript">
|
||||
function postPlayerEvent(eventName, eventData) {
|
||||
window.webkit.messageHandlers.performAction.postMessage({'event': eventName, 'data': eventData});
|
||||
};
|
||||
|
||||
var video;
|
||||
var hls;
|
||||
|
||||
var isManifestParsed = false;
|
||||
var isFirstFrameReady = false;
|
||||
|
||||
var currentTimeUpdateTimeout = null;
|
||||
|
||||
function playerInitialize(params) {
|
||||
video = document.getElementById('videoPlayer');
|
||||
|
||||
video.addEventListener('loadeddata', (event) => {
|
||||
if (!isFirstFrameReady) {
|
||||
isFirstFrameReady = true;
|
||||
refreshPlayerStatus();
|
||||
}
|
||||
});
|
||||
video.addEventListener("playing", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("pause", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("seeking", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
video.addEventListener("waiting", function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls = new Hls({
|
||||
startLevel: 0,
|
||||
testBandwidth: false,
|
||||
debug: params['debug'],
|
||||
autoStartLoad: false
|
||||
});
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, function() {
|
||||
isManifestParsed = true;
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls.on(Hls.Events.LEVEL_SWITCHED, function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
hls.on(Hls.Events.LEVELS_UPDATED, function() {
|
||||
refreshPlayerStatus();
|
||||
});
|
||||
|
||||
hls.loadSource('master.m3u8');
|
||||
hls.attachMedia(video);
|
||||
}
|
||||
|
||||
function playerLoad(initialLevelIndex) {
|
||||
hls.startLevel = initialLevelIndex;
|
||||
hls.startLoad(startPosition=-1);
|
||||
}
|
||||
|
||||
function playerPlay() {
|
||||
video.play();
|
||||
}
|
||||
|
||||
function playerPause() {
|
||||
video.pause();
|
||||
}
|
||||
|
||||
function playerSetBaseRate(value) {
|
||||
video.playbackRate = value;
|
||||
}
|
||||
|
||||
function playerSetLevel(level) {
|
||||
if (level >= 0) {
|
||||
hls.autoLevelEnabled = false;
|
||||
hls.currentLevel = level;
|
||||
} else {
|
||||
hls.autoLevelEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function playerSeek(value) {
|
||||
video.currentTime = value;
|
||||
}
|
||||
|
||||
function playerSetIsMuted(value) {
|
||||
video.muted = value;
|
||||
}
|
||||
|
||||
function getLevels() {
|
||||
var levels = [];
|
||||
for (var i = 0; i < hls.levels.length; i++) {
|
||||
level = hls.levels[i];
|
||||
levels.push({
|
||||
'index': i,
|
||||
'bitrate': level.bitrate || 0,
|
||||
'width': level.width || 0,
|
||||
'height': level.height || 0
|
||||
});
|
||||
}
|
||||
return levels;
|
||||
}
|
||||
|
||||
function refreshPlayerStatus() {
|
||||
var isPlaying = false;
|
||||
if (!video.paused && !video.ended && video.readyState > 2) {
|
||||
isPlaying = true;
|
||||
}
|
||||
|
||||
postPlayerEvent('playerStatus', {
|
||||
'isReady': isManifestParsed,
|
||||
'isFirstFrameReady': isFirstFrameReady,
|
||||
'isPlaying': !video.paused,
|
||||
'rate': isPlaying ? video.playbackRate : 0.0,
|
||||
'defaultRate': video.playbackRate,
|
||||
'levels': getLevels(),
|
||||
'currentLevel': hls.currentLevel
|
||||
});
|
||||
|
||||
refreshPlayerCurrentTime();
|
||||
|
||||
if (isPlaying) {
|
||||
if (currentTimeUpdateTimeout == null) {
|
||||
currentTimeUpdateTimeout = setTimeout(() => {
|
||||
refreshPlayerCurrentTime();
|
||||
}, 200);
|
||||
}
|
||||
} else {
|
||||
if(currentTimeUpdateTimeout != null){
|
||||
clearTimeout(currentTimeUpdateTimeout);
|
||||
currentTimeUpdateTimeout = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPlayerCurrentTime() {
|
||||
postPlayerEvent('playerCurrentTime', {
|
||||
'value': video.currentTime
|
||||
});
|
||||
currentTimeUpdateTimeout = setTimeout(() => {
|
||||
refreshPlayerCurrentTime()
|
||||
}, 200);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<video id="videoPlayer" playsinline></video>
|
||||
</body>
|
||||
</html>
|
29290
submodules/TelegramUI/Resources/WebEmbed/hls.js
Normal file
29290
submodules/TelegramUI/Resources/WebEmbed/hls.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
private var contentNodeSnapshot: UIView?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(tapped: @escaping () -> Void) {
|
||||
self.tapped = tapped
|
||||
@ -58,9 +58,9 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
self.progressNode.status = contentNode.status
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -74,15 +74,15 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
if let snapshot = snapshot {
|
||||
self.contentContainerNode.view.addSubview(snapshot)
|
||||
if let _ = self.validLayoutSize {
|
||||
if let _ = self.validLayout {
|
||||
snapshot.frame = CGRect(origin: CGPoint(), size: snapshot.frame.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
self.contentContainerNode.cornerRadius = size.width / 2.0
|
||||
|
||||
@ -96,7 +96,7 @@ final class OverlayInstantVideoDecoration: UniversalVideoDecoration {
|
||||
transition.updateFrame(node: self.contentContainerNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -0.5, dy: -0.5))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
|
||||
if let contentNodeSnapshot = self.contentNodeSnapshot {
|
||||
|
@ -16,7 +16,7 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
private let inset: CGFloat
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init(inset: CGFloat, backgroundImage: UIImage?, tapped: @escaping () -> Void) {
|
||||
self.inset = inset
|
||||
@ -51,9 +51,9 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,8 +63,8 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let diameter = size.width + inset
|
||||
self.contentContainerNode.cornerRadius = (diameter - 3.0) / 2.0
|
||||
@ -80,7 +80,7 @@ public final class ChatBubbleInstantVideoDecoration: UniversalVideoDecoration {
|
||||
self.contentContainerNode.subnodeTransform = CATransform3DMakeScale((contentFrame.width + 2.0) / contentFrame.width, (contentFrame.width + 2.0) / contentFrame.width, 1.0)
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
contentNode.updateLayout(size: size, transition: transition)
|
||||
contentNode.updateLayout(size: size, actualSize: actualSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private var contentNode: (ASDisplayNode & UniversalVideoContentNode)?
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
public init(corners: ImageCorners, nativeSize: CGSize, contentMode: ChatBubbleVideoDecorationContentMode, backgroundColor: UIColor) {
|
||||
self.corners = corners
|
||||
@ -82,23 +82,23 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let size = self.validLayoutSize {
|
||||
if let validLayout = self.validLayout {
|
||||
var scaledSize: CGSize
|
||||
switch self.contentMode {
|
||||
case .aspectFit:
|
||||
scaledSize = self.nativeSize.aspectFitted(size)
|
||||
scaledSize = self.nativeSize.aspectFitted(validLayout.size)
|
||||
case .aspectFill:
|
||||
scaledSize = self.nativeSize.aspectFilled(size)
|
||||
scaledSize = self.nativeSize.aspectFilled(validLayout.size)
|
||||
}
|
||||
if abs(scaledSize.width - size.width) < 2.0 {
|
||||
scaledSize.width = size.width
|
||||
if abs(scaledSize.width - validLayout.size.width) < 2.0 {
|
||||
scaledSize.width = validLayout.size.width
|
||||
}
|
||||
if abs(scaledSize.height - size.height) < 2.0 {
|
||||
scaledSize.height = size.height
|
||||
if abs(scaledSize.height - validLayout.size.height) < 2.0 {
|
||||
scaledSize.height = validLayout.size.height
|
||||
}
|
||||
|
||||
contentNode.frame = CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize)
|
||||
contentNode.updateLayout(size: scaledSize, transition: .immediate)
|
||||
contentNode.frame = CGRect(origin: CGPoint(x: floor((validLayout.size.width - scaledSize.width) / 2.0), y: floor((validLayout.size.height - scaledSize.height) / 2.0)), size: scaledSize)
|
||||
contentNode.updateLayout(size: scaledSize, actualSize: scaledSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -108,8 +108,8 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
public func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
public func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
@ -137,7 +137,7 @@ public final class ChatBubbleVideoDecoration: UniversalVideoDecoration {
|
||||
scaledSize.height = size.height
|
||||
}
|
||||
transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: floor((size.width - scaledSize.width) / 2.0), y: floor((size.height - scaledSize.height) / 2.0)), size: scaledSize))
|
||||
contentNode.updateLayout(size: scaledSize, transition: transition)
|
||||
contentNode.updateLayout(size: scaledSize, actualSize: scaledSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -217,7 +217,7 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
private var dimensions: CGSize?
|
||||
private let dimensionsPromise = ValuePromise<CGSize>(CGSize())
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
private var shouldPlay: Bool = false
|
||||
|
||||
@ -306,8 +306,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
if let dimensions = getSize() {
|
||||
strongSelf.dimensions = dimensions
|
||||
strongSelf.dimensionsPromise.set(dimensions)
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, transition: .immediate)
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -432,8 +432,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
if let dimensions = self.dimensions {
|
||||
let imageSize = CGSize(width: floor(dimensions.width / 2.0), height: floor(dimensions.height / 2.0))
|
||||
|
@ -47,7 +47,7 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
private let statusDisposable = MetaDisposable()
|
||||
|
||||
private var validLayoutSize: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(contentDimensions: CGSize, unminimize: @escaping () -> Void, togglePlayPause: @escaping () -> Void, expand: @escaping () -> Void, close: @escaping () -> Void, controlsAreShowingUpdated: @escaping (Bool) -> Void) {
|
||||
self.contentDimensions = contentDimensions
|
||||
@ -106,9 +106,9 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
if let contentNode = contentNode {
|
||||
if contentNode.supernode !== self.contentContainerNode {
|
||||
self.contentContainerNode.addSubnode(contentNode)
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
contentNode.frame = self.frameForContent(size: validLayoutSize)
|
||||
contentNode.updateLayout(size: validLayoutSize, transition: .immediate)
|
||||
if let validLayout = self.validLayout {
|
||||
contentNode.frame = self.frameForContent(size: validLayout.size)
|
||||
contentNode.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,8 +118,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
func updateContentNodeSnapshot(_ snapshot: UIView?) {
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayoutSize = size
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, actualSize)
|
||||
|
||||
let contentFrame = self.frameForContent(size: size)
|
||||
|
||||
@ -146,7 +146,7 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
|
||||
if let contentNode = self.contentNode {
|
||||
transition.updateFrame(node: contentNode, frame: contentFrame)
|
||||
contentNode.updateLayout(size: contentFrame.size, transition: transition)
|
||||
contentNode.updateLayout(size: contentFrame.size, actualSize: contentFrame.size, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,8 +209,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
if self.minimizedBlurView == nil {
|
||||
let minimizedBlurView = UIVisualEffectView(effect: nil)
|
||||
self.minimizedBlurView = minimizedBlurView
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
minimizedBlurView.frame = CGRect(origin: CGPoint(), size: validLayoutSize)
|
||||
if let validLayout = self.validLayout {
|
||||
minimizedBlurView.frame = CGRect(origin: CGPoint(), size: validLayout.size)
|
||||
}
|
||||
minimizedBlurView.isHidden = true
|
||||
self.foregroundContainerNode.view.addSubview(minimizedBlurView)
|
||||
@ -222,8 +222,8 @@ final class OverlayVideoDecoration: UniversalVideoDecoration {
|
||||
self.minimizedBlurView?.contentView.addSubview(minimizedArrowView)
|
||||
}
|
||||
if let minimizedArrowView = self.minimizedArrowView {
|
||||
if let validLayoutSize = self.validLayoutSize {
|
||||
setupArrowFrame(size: validLayoutSize, edge: edge, view: minimizedArrowView)
|
||||
if let validLayout = self.validLayout {
|
||||
setupArrowFrame(size: validLayout.size, edge: edge, view: minimizedArrowView)
|
||||
}
|
||||
minimizedArrowView.setAngled(!adjusting, animated: true)
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
private var dimensions: CGSize?
|
||||
private let dimensionsPromise = ValuePromise<CGSize>(CGSize())
|
||||
|
||||
private var validLayout: CGSize?
|
||||
private var validLayout: (size: CGSize, actualSize: CGSize)?
|
||||
|
||||
init(postbox: Postbox, audioSessionManager: ManagedAudioSession, userLocation: MediaResourceUserLocation, content: PlatformVideoContent.Content, streamVideo: Bool, loopVideo: Bool, enableSound: Bool, baseRate: Double, fetchAutomatically: Bool) {
|
||||
self.postbox = postbox
|
||||
@ -203,8 +203,8 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
if let dimensions = getSize() {
|
||||
strongSelf.dimensions = dimensions
|
||||
strongSelf.dimensionsPromise.set(dimensions)
|
||||
if let size = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: size, transition: .immediate)
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
strongSelf.updateLayout(size: validLayout.size, actualSize: validLayout.actualSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -371,7 +371,7 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -207,7 +207,7 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -116,7 +116,7 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
|
||||
self.readyDisposable.dispose()
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, actualSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updatePosition(node: self.playerNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
|
||||
transition.updateTransformScale(node: self.playerNode, scale: size.width / self.intrinsicDimensions.width)
|
||||
|
||||
|
@ -336,6 +336,10 @@ public final class ExternalMediaStreamingContext: SharedHLSServerSource {
|
||||
impl.fileData(id: id, range: range).start(next: subscriber.putNext)
|
||||
}
|
||||
}
|
||||
|
||||
public func arbitraryFileData(path: String) -> Signal<(data: Data, contentType: String)?, NoError> {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|
||||
public protocol SharedHLSServerSource: AnyObject {
|
||||
@ -345,6 +349,7 @@ public protocol SharedHLSServerSource: AnyObject {
|
||||
func playlistData(quality: Int) -> Signal<String, NoError>
|
||||
func partData(index: Int, quality: Int) -> Signal<Data?, NoError>
|
||||
func fileData(id: Int64, range: Range<Int>) -> Signal<(TempBoxFile, Range<Int>, Int)?, NoError>
|
||||
func arbitraryFileData(path: String) -> Signal<(data: Data, contentType: String)?, NoError>
|
||||
}
|
||||
|
||||
@available(iOS 12.0, macOS 14.0, *)
|
||||
@ -651,7 +656,19 @@ public final class SharedHLSServer {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
self.sendErrorAndClose(connection: connection, error: .notFound)
|
||||
let _ = (source.arbitraryFileData(path: filePath)
|
||||
|> deliverOn(self.queue)
|
||||
|> take(1)).start(next: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let result {
|
||||
self.sendResponseAndClose(connection: connection, data: result.data, contentType: result.contentType)
|
||||
} else {
|
||||
self.sendErrorAndClose(connection: connection, error: .notFound)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -665,13 +682,14 @@ public final class SharedHLSServer {
|
||||
})
|
||||
}
|
||||
|
||||
private func sendResponseAndClose(connection: NWConnection, data: Data, range: Range<Int>? = nil, totalSize: Int? = nil) {
|
||||
private func sendResponseAndClose(connection: NWConnection, data: Data, contentType: String = "application/octet-stream", range: Range<Int>? = nil, totalSize: Int? = nil) {
|
||||
var responseHeaders = "HTTP/1.1 200 OK\r\n"
|
||||
responseHeaders.append("Content-Length: \(data.count)\r\n")
|
||||
if let range, let totalSize {
|
||||
responseHeaders.append("Content-Range: bytes \(range.lowerBound)-\(range.upperBound)/\(totalSize)\r\n")
|
||||
}
|
||||
responseHeaders.append("Content-Type: application/octet-stream\r\n")
|
||||
|
||||
responseHeaders.append("Content-Type: \(contentType)\r\n")
|
||||
responseHeaders.append("Connection: close\r\n")
|
||||
responseHeaders.append("Access-Control-Allow-Origin: *\r\n")
|
||||
responseHeaders.append("\r\n")
|
||||
|
Loading…
x
Reference in New Issue
Block a user