Inline video playback fixes

This commit is contained in:
Ilya Laktyushin 2019-02-17 15:18:06 +04:00
parent a98aa3e57f
commit 1a865367a1
14 changed files with 188 additions and 121 deletions

View File

@ -334,7 +334,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
var updateInlineImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
var textCutout = TextNodeCutout()
var initialWidth: CGFloat = CGFloat.greatestFiniteMagnitude
var refineContentImageLayout: ((CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode)))?
var refineContentImageLayout: ((CGSize, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode)))?
var refineContentFileLayout: ((CGSize) -> (CGFloat, (CGFloat) -> (CGSize, () -> ChatMessageInteractiveFileNode)))?
var contentInstantVideoSizeAndApply: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ContainedViewLayoutTransition) -> ChatMessageInteractiveInstantVideoNode)?
@ -377,6 +377,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
textString = string.attributedSubstring(from: NSMakeRange(0, 1000))
}
var automaticPlayback = false
if let (media, flags) = mediaAndFlags {
if let file = media as? TelegramMediaFile {
if file.isInstantVideo {
@ -386,7 +388,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
contentInstantVideoSizeAndApply = (videoLayout, apply)
} else if file.isVideo {
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
var automaticPlayback = false
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file) {
automaticDownload = .full
@ -395,18 +396,25 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
}
if file.isAnimated {
automaticPlayback = automaticDownloadSettings.autoplayGifs
} else {
if case .full = automaticDownload, automaticDownloadSettings.autoplayVideos {
} else if file.isVideo && automaticDownloadSettings.autoplayVideos {
var willDownloadOrLocal = false
if case .full = automaticDownload {
willDownloadOrLocal = true
} else {
willDownloadOrLocal = context.account.postbox.mediaBox.completedResourcePath(file.resource) != nil
}
if willDownloadOrLocal {
automaticPlayback = true
contentMode = .aspectFill
}
}
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, file, automaticDownload, associatedData.automaticDownloadPeerType, automaticPlayback, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, file, automaticDownload, associatedData.automaticDownloadPeerType, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
refineContentImageLayout = refineLayout
} else if file.isSticker, let _ = file.dimensions {
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, file, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, automaticDownloadSettings.autoplayGifs, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, file, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
refineContentImageLayout = refineLayout
} else {
@ -431,7 +439,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
} else if let image = media as? TelegramMediaImage {
if !flags.contains(.preferMediaInline) {
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: image)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, image, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, false, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, image, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
refineContentImageLayout = refineLayout
} else if let dimensions = largestImageRepresentation(image.representations)?.dimensions {
@ -443,11 +451,11 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
}
} else if let image = media as? TelegramMediaWebFile {
let automaticDownload = shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: image)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, image, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, false, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, image, automaticDownload ? .full : .none, associatedData.automaticDownloadPeerType, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
refineContentImageLayout = refineLayout
} else if let wallpaper = media as? WallpaperPreviewMedia {
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, wallpaper, .full, associatedData.automaticDownloadPeerType, false, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
let (_, initialImageWidth, refineLayout) = contentImageLayout(context, presentationData.theme.theme, presentationData.strings, message, wallpaper, .full, associatedData.automaticDownloadPeerType, .constrained(CGSize(width: constrainedSize.width - horizontalInsets.left - horizontalInsets.right, height: constrainedSize.height)), layoutConstants, contentMode)
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
refineContentImageLayout = refineLayout
}
@ -588,7 +596,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
var finalizeContentImageLayout: ((CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))?
if let refineContentImageLayout = refineContentImageLayout {
let (refinedWidth, finalizeImageLayout) = refineContentImageLayout(textConstrainedSize, ImageCorners(radius: 4.0))
let (refinedWidth, finalizeImageLayout) = refineContentImageLayout(textConstrainedSize, automaticPlayback, ImageCorners(radius: 4.0))
finalizeContentImageLayout = finalizeImageLayout
boundingSize.width = max(boundingSize.width, refinedWidth)
@ -715,6 +723,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
adjustedStatusFrame = CGRect(origin: CGPoint(x: boundingWidth - statusFrame.size.width - insets.right, y: statusFrame.origin.y), size: statusFrame.size)
}
adjustedBoundingSize.width = max(boundingWidth, adjustedBoundingSize.width)
return (adjustedBoundingSize, { [weak self] animation, synchronousLoads in
if let strongSelf = self {
strongSelf.context = context
@ -796,13 +806,12 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
}
strongSelf.additionalImageBadgeNode = updatedAdditionalImageBadge
contentImageNode.addSubnode(updatedAdditionalImageBadge)
updatedAdditionalImageBadge.update(theme: presentationData.theme.theme, content: additionalImageBadgeContent, mediaDownloadState: nil, animated: false)
if mediaBadge != nil {
updatedAdditionalImageBadge.contentMode = .topLeft
updatedAdditionalImageBadge.update(theme: presentationData.theme.theme, content: additionalImageBadgeContent, mediaDownloadState: nil, animated: false)
updatedAdditionalImageBadge.frame = CGRect(origin: CGPoint(x: 2.0, y: 2.0), size: CGSize(width: 0.0, height: 0.0))
} else {
updatedAdditionalImageBadge.contentMode = .topRight
updatedAdditionalImageBadge.frame = CGRect(origin: CGPoint(x: contentImageSize.width - 2.0, y: contentImageSize.height - 18.0 - 2.0), size: CGSize(width: 0.0, height: 0.0))
updatedAdditionalImageBadge.update(theme: presentationData.theme.theme, content: additionalImageBadgeContent, mediaDownloadState: nil, alignment: .right, animated: false)
updatedAdditionalImageBadge.frame = CGRect(origin: CGPoint(x: contentImageSize.width - 6.0, y: contentImageSize.height - 18.0 - 6.0), size: CGSize(width: 0.0, height: 0.0))
}
} else if let additionalImageBadgeNode = strongSelf.additionalImageBadgeNode {
strongSelf.additionalImageBadgeNode = nil

View File

@ -23,7 +23,7 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
topRightCorner = .Corner(mergedRadius)
}
}
case let .mosaic(position):
case let .mosaic(position, _):
switch position.topLeft {
case .none:
topLeftCorner = .Corner(normalRadius)
@ -69,7 +69,7 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
bottomRightCorner = .Corner(mergedRadius)
}
}
case let .mosaic(position):
case let .mosaic(position, _):
switch position.bottomLeft {
case let .none(tail):
if tail {

View File

@ -54,7 +54,7 @@ struct ChatMessageBubbleContentMosaicPosition {
enum ChatMessageBubbleContentPosition {
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
case mosaic(position: ChatMessageBubbleContentMosaicPosition)
case mosaic(position: ChatMessageBubbleContentMosaicPosition, wide: Bool)
}
enum ChatMessageBubblePreparePosition {

View File

@ -976,7 +976,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
}
}
let (_, contentNodeFinalize) = contentNodeLayout(framesAndPositions[mosaicIndex].0.size, .mosaic(position: ChatMessageBubbleContentMosaicPosition(topLeft: topLeft, topRight: topRight, bottomLeft: bottomLeft, bottomRight: bottomRight)))
let (_, contentNodeFinalize) = contentNodeLayout(framesAndPositions[mosaicIndex].0.size, .mosaic(position: ChatMessageBubbleContentMosaicPosition(topLeft: topLeft, topRight: topRight, bottomLeft: bottomLeft, bottomRight: bottomRight), wide: position.isWide))
contentNodePropertiesAndFinalize.append((contentNodeProperties, contentNodeFinalize))

View File

@ -18,6 +18,10 @@ struct MosaicItemPosition: OptionSet {
static let right = MosaicItemPosition(rawValue: 8)
static let inside = MosaicItemPosition(rawValue: 16)
static let unknown = MosaicItemPosition(rawValue: 65536)
var isWide: Bool {
return self.contains(.left) && self.contains(.right) && (self.contains(.top) || self.contains(.bottom))
}
}
private struct MosaicItemInfo {

View File

@ -76,55 +76,9 @@ final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
}
}
func update(theme: PresentationTheme, content: ChatMessageInteractiveMediaBadgeContent?, mediaDownloadState: ChatMessageInteractiveMediaDownloadState?, animated: Bool) {
func update(theme: PresentationTheme, content: ChatMessageInteractiveMediaBadgeContent?, mediaDownloadState: ChatMessageInteractiveMediaDownloadState?, alignment: NSTextAlignment = .left, animated: Bool) {
var transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
if self.mediaDownloadState != mediaDownloadState {
self.mediaDownloadState = mediaDownloadState
if let mediaDownloadState = self.mediaDownloadState {
let mediaDownloadStatusNode: RadialStatusNode
if let current = self.mediaDownloadStatusNode {
mediaDownloadStatusNode = current
} else {
mediaDownloadStatusNode = RadialStatusNode(backgroundNodeColor: .clear)
self.mediaDownloadStatusNode = mediaDownloadStatusNode
self.addSubnode(mediaDownloadStatusNode)
}
let state: RadialStatusNodeState
var isCompact = false
switch mediaDownloadState {
case .remote:
if let image = PresentationResourcesChat.chatBubbleFileCloudFetchMediaIcon(theme) {
state = .customIcon(image)
} else {
state = .none
}
case let .fetching(progress):
var cloudProgress: CGFloat?
if let progress = progress {
cloudProgress = CGFloat(progress)
}
state = .cloudProgress(color: .white, strokeBackgroundColor: UIColor(white: 1.0, alpha: 0.3), lineWidth: 2.0 - UIScreenPixel, value: cloudProgress)
case .compactRemote:
state = .download(.white)
isCompact = true
case .compactFetching:
state = .progress(color: .white, lineWidth: nil, value: 0.0, cancelEnabled: true)
isCompact = true
}
let mediaStatusFrame: CGRect
if isCompact {
mediaStatusFrame = CGRect(origin: CGPoint(x: 1.0, y: -1.0), size: CGSize(width: 20.0, height: 20.0))
} else {
mediaStatusFrame = CGRect(origin: CGPoint(x: 7.0, y: 6.0), size: CGSize(width: 28.0, height: 28.0))
}
mediaDownloadStatusNode.frame = mediaStatusFrame
mediaDownloadStatusNode.transitionToState(state, animated: true, completion: {})
} else if let mediaDownloadStatusNode = self.mediaDownloadStatusNode {
mediaDownloadStatusNode.transitionToState(.none, animated: true, completion: {})
}
}
var contentSize = CGSize()
if self.content != content {
@ -238,7 +192,65 @@ final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
contentSize = CGSize(width: contentWidth, height: active ? 38.0 : 18.0)
}
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(x: 0.0, y: 0.0, width: contentSize.width, height: contentSize.height))
var originX: CGFloat = 0.0
if alignment == .right {
originX = -contentSize.width
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(x: originX, y: 0.0, width: contentSize.width, height: contentSize.height))
}
if self.mediaDownloadState != mediaDownloadState {
self.mediaDownloadState = mediaDownloadState
if let mediaDownloadState = self.mediaDownloadState {
let mediaDownloadStatusNode: RadialStatusNode
if let current = self.mediaDownloadStatusNode {
mediaDownloadStatusNode = current
} else {
mediaDownloadStatusNode = RadialStatusNode(backgroundNodeColor: .clear)
self.mediaDownloadStatusNode = mediaDownloadStatusNode
self.addSubnode(mediaDownloadStatusNode)
}
let state: RadialStatusNodeState
var isCompact = false
var originX: CGFloat = 0.0
if alignment == .right {
originX -= contentSize.width
}
var originY: CGFloat = 6.0
switch mediaDownloadState {
case .remote:
if let image = PresentationResourcesChat.chatBubbleFileCloudFetchMediaIcon(theme) {
state = .customIcon(image)
} else {
state = .none
}
case let .fetching(progress):
var cloudProgress: CGFloat?
if let progress = progress {
cloudProgress = CGFloat(progress)
}
state = .cloudProgress(color: .white, strokeBackgroundColor: UIColor(white: 1.0, alpha: 0.3), lineWidth: 2.0 - UIScreenPixel, value: cloudProgress)
case .compactRemote:
state = .download(.white)
isCompact = true
originY = -1.0 - UIScreenPixel
case .compactFetching:
state = .progress(color: .white, lineWidth: nil, value: 0.0, cancelEnabled: true)
isCompact = true
originY = -1.0
}
let mediaStatusFrame: CGRect
if isCompact {
mediaStatusFrame = CGRect(origin: CGPoint(x: 1.0 + originX, y: originY), size: CGSize(width: 20.0, height: 20.0))
} else {
mediaStatusFrame = CGRect(origin: CGPoint(x: 7.0 + originX, y: originY), size: CGSize(width: 28.0, height: 28.0))
}
mediaDownloadStatusNode.frame = mediaStatusFrame
mediaDownloadStatusNode.transitionToState(state, animated: true, completion: {})
} else if let mediaDownloadStatusNode = self.mediaDownloadStatusNode {
mediaDownloadStatusNode.transitionToState(.none, animated: true, completion: {})
}
}
}

View File

@ -186,7 +186,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
}
}
func asyncLayout() -> (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void))) {
func asyncLayout() -> (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void))) {
let currentMessage = self.message
let currentMedia = self.media
let imageLayout = self.imageNode.asyncLayout()
@ -195,7 +195,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
let hasCurrentVideoNode = currentVideoNode != nil
let previousAutomaticDownload = self.automaticDownload
return { [weak self] context, theme, strings, message, media, automaticDownload, peerType, automaticPlayback, sizeCalculation, layoutConstants, contentMode in
return { [weak self] context, theme, strings, message, media, automaticDownload, peerType, sizeCalculation, layoutConstants, contentMode in
var nativeSize: CGSize
let isSecretMedia = message.containsSecretMedia
@ -244,7 +244,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
} else if file.isSticker {
unboundSize = unboundSize.aspectFilled(CGSize(width: 162.0, height: 162.0))
}
isInlinePlayableVideo = file.isVideo && !isSecretMedia && automaticPlayback
isInlinePlayableVideo = file.isVideo && !isSecretMedia
} else if let image = media as? TelegramMediaWebFile, let dimensions = image.dimensions {
unboundSize = CGSize(width: floor(dimensions.width * 0.5), height: floor(dimensions.height * 0.5))
} else if let wallpaper = media as? WallpaperPreviewMedia {
@ -288,9 +288,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
let _ = PresentationResourcesChat.chatBubbleSecretMediaIcon(theme)
}
return (nativeSize, maxWidth, { constrainedSize, corners in
return (nativeSize, maxWidth, { constrainedSize, automaticPlayback, corners in
var resultWidth: CGFloat
isInlinePlayableVideo = isInlinePlayableVideo && automaticPlayback
switch sizeCalculation {
case .constrained:
if isSecretMedia {
@ -585,7 +587,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
updatedPlayerStatusSignal = videoNode.status
|> mapToSignal { status -> Signal<MediaPlayerStatus?, NoError> in
if let status = status, case .buffering = status.status {
return .complete() |> delay(0.3, queue: Queue.mainQueue())
return .complete() |> delay(0.5, queue: Queue.mainQueue())
} else {
return .single(status)
}
@ -906,7 +908,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
} else {
if automaticPlayback {
mediaDownloadState = .fetching(progress: nil)
mediaDownloadState = .fetching(progress: progress)
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
} else {
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: sizeString, size: nil, muted: false, active: false)
@ -920,23 +922,37 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: strings.Conversation_Processing, size: nil, muted: false, active: active)
}
} else {
if isMediaStreamable(message: message, media: file), let _ = file.size {
if isMediaStreamable(message: message, media: file), let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true)) / \(dataSizeString(size, forceDecimal: true))"
if automaticPlayback && !message.flags.contains(.Unsent), let duration = file.duration {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
badgeContent = .text(inset: 0.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: durationString))
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
mediaDownloadState = .fetching(progress: automaticPlayback ? nil : progress)
if self.playerStatus?.status == .playing {
mediaDownloadState = nil
}
} else {
let progressString = String(format: "%d%%", Int(progress * 100.0))
badgeContent = .text(inset: message.flags.contains(.Unsent) ? 0.0 : 12.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: progressString))
mediaDownloadState = automaticPlayback ? .none : .compactFetching(progress: progress)
}
if !message.flags.contains(.Unsent) {
mediaDownloadState = automaticPlayback ? .none : .compactFetching(progress: progress)
state = .none
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
}
} else {
if let duration = file.duration, !file.isAnimated {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
badgeContent = .text(inset: 0.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: durationString))
if automaticPlayback, let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true)) / \(dataSizeString(size, forceDecimal: true))"
mediaDownloadState = .fetching(progress: progress)
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
} else {
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: nil, muted: false, active: active)
}
}
state = automaticPlayback ? .none : state
@ -960,11 +976,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
} else if let file = media as? TelegramMediaFile {
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && automaticPlayback
if !isInlinePlayableVideo && file.isVideo {
if case .constrained = sizeCalculation {
state = .play(bubbleTheme.mediaOverlayControlForegroundColor)
} else {
state = .none
}
state = .play(bubbleTheme.mediaOverlayControlForegroundColor)
} else {
state = .none
}
@ -977,11 +989,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
}
if let file = media as? TelegramMediaFile, let duration = file.duration, !file.isAnimated {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
if case .constrained = sizeCalculation {
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: nil, muted: muted, active: false)
} else {
badgeContent = .text(inset: 0.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: durationString))
}
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: nil, muted: muted, active: false)
}
case .Remote:
state = .download(bubbleTheme.mediaOverlayControlForegroundColor)
@ -998,7 +1006,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
}
} else {
if isMediaStreamable(message: message, media: file) {
state = .none
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
badgeContent = .text(inset: 12.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: durationString))
mediaDownloadState = .compactRemote
} else {
@ -1075,12 +1083,12 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
}
}
static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))) {
static func asyncLayout(_ node: ChatMessageInteractiveMediaNode?) -> (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))) {
let currentAsyncLayout = node?.asyncLayout()
return { context, theme, strings, message, media, automaticDownload, peerType, automaticPlayback, sizeCalculation, layoutConstants, contentMode in
return { context, theme, strings, message, media, automaticDownload, peerType, sizeCalculation, layoutConstants, contentMode in
var imageNode: ChatMessageInteractiveMediaNode
var imageLayout: (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ automaticPlayback: Bool, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void)))
var imageLayout: (_ context: AccountContext, _ theme: PresentationTheme, _ strings: PresentationStrings, _ message: Message, _ media: Media, _ automaticDownload: InteractiveMediaNodeAutodownloadMode, _ peerType: AutomaticMediaDownloadPeerType, _ sizeCalculation: InteractiveMediaNodeSizeCalculation, _ layoutConstants: ChatMessageItemLayoutConstants, _ contentMode: InteractiveMediaNodeContentMode) -> (CGSize, CGFloat, (CGSize, Bool, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> Void)))
if let node = node, let currentAsyncLayout = currentAsyncLayout {
imageNode = node
@ -1090,10 +1098,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
imageLayout = imageNode.asyncLayout()
}
let (unboundSize, initialWidth, continueLayout) = imageLayout(context, theme, strings, message, media, automaticDownload, peerType, automaticPlayback, sizeCalculation, layoutConstants, contentMode)
let (unboundSize, initialWidth, continueLayout) = imageLayout(context, theme, strings, message, media, automaticDownload, peerType, sizeCalculation, layoutConstants, contentMode)
return (unboundSize, initialWidth, { constrainedSize, corners in
let (finalWidth, finalLayout) = continueLayout(constrainedSize, corners)
return (unboundSize, initialWidth, { constrainedSize, automaticPlayback, corners in
let (finalWidth, finalLayout) = continueLayout(constrainedSize, automaticPlayback, corners)
return (finalWidth, { boundingWidth in
let (finalSize, apply) = finalLayout(boundingWidth)

View File

@ -81,7 +81,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
if telegramFile.isAnimated {
automaticPlayback = item.controllerInteraction.automaticMediaDownloadSettings.autoplayGifs
contentMode = .aspectFill
} else if telegramFile.isVideo && item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos, case .linear = preparePosition {
} else if telegramFile.isVideo && item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos {
var willDownloadOrLocal = false
if case .full = automaticDownload {
willDownloadOrLocal = true
@ -121,12 +121,16 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
sizeCalculation = .unconstrained
}
let (unboundSize, initialWidth, refineLayout) = interactiveImageLayout(item.context, item.presentationData.theme.theme, item.presentationData.strings, item.message, selectedMedia!, automaticDownload, item.associatedData.automaticDownloadPeerType, automaticPlayback, sizeCalculation, layoutConstants, contentMode)
let (unboundSize, initialWidth, refineLayout) = interactiveImageLayout(item.context, item.presentationData.theme.theme, item.presentationData.strings, item.message, selectedMedia!, automaticDownload, item.associatedData.automaticDownloadPeerType, sizeCalculation, layoutConstants, contentMode)
let forceFullCorners = false
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 7.0, hidesBackground: .emptyWallpaper, forceFullCorners: forceFullCorners, forceAlignment: .none)
return (contentProperties, unboundSize, initialWidth + bubbleInsets.left + bubbleInsets.right, { constrainedSize, position in
if case let .mosaic(_, wide) = position {
automaticPlayback = automaticPlayback && wide
}
var updatedPosition: ChatMessageBubbleContentPosition = position
if forceFullCorners, case .linear = updatedPosition {
updatedPosition = .linear(top: .None(.None(.None)), bottom: .None(.None(.None)))
@ -136,7 +140,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
let imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: updatedPosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius)
let (refinedWidth, finishLayout) = refineLayout(CGSize(width: constrainedSize.width - bubbleInsets.left - bubbleInsets.right, height: constrainedSize.height), imageCorners)
let (refinedWidth, finishLayout) = refineLayout(CGSize(width: constrainedSize.width - bubbleInsets.left - bubbleInsets.right, height: constrainedSize.height), automaticPlayback, imageCorners)
return (refinedWidth + bubbleInsets.left + bubbleInsets.right, { boundingWidth in
let (imageSize, imageApply) = finishLayout(boundingWidth - bubbleInsets.left - bubbleInsets.right)

View File

@ -229,9 +229,16 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
var mainMedia: Media?
var automaticPlayback = false
if let file = webpage.file, !file.isAnimated, item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos {
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
if shouldDownloadMediaAutomatically(settings: item.controllerInteraction.automaticMediaDownloadSettings, peerType: item.associatedData.automaticDownloadPeerType, networkType: item.associatedData.automaticDownloadNetworkType, authorPeerId: item.message.author?.id, contactsPeerIds: item.associatedData.contactsPeerIds, media: file) {
automaticDownload = .full
}
if case .full = automaticDownload {
automaticPlayback = true
} else {
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(file.resource) != nil
}
}

View File

@ -8,7 +8,7 @@ import Display
import UIKit
import AVFoundation
private func resourceData(account: Account, resource: MediaResource, chunkSize: Int) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
private func videoFirstFrameData(account: Account, resource: MediaResource, chunkSize: Int) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
if let size = resource.size {
return account.postbox.mediaBox.resourceData(resource, size: size, in: 0 ..< min(size, chunkSize))
|> mapToSignal { _ -> Signal<CachedMediaResourceRepresentationResult, NoError> in
@ -19,7 +19,7 @@ private func resourceData(account: Account, resource: MediaResource, chunkSize:
if chunkSize > size {
return .complete()
} else {
return resourceData(account: account, resource: resource, chunkSize: chunkSize + chunkSize)
return videoFirstFrameData(account: account, resource: resource, chunkSize: chunkSize + chunkSize)
}
}
}
@ -55,7 +55,7 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR
return .complete()
}
} else if let size = resource.size {
return resourceData(account: account, resource: resource, chunkSize: min(size, 64 * 1024))
return videoFirstFrameData(account: account, resource: resource, chunkSize: min(size, 192 * 1024))
} else {
return .complete()
}

View File

@ -143,7 +143,6 @@ final class GridMessageItemNode: GridItemNode {
private var item: GridMessageItem?
private var controllerInteraction: ChatControllerInteraction?
private var statusNode: RadialStatusNode
//private let videoAccessoryNode = GridMessageVideoAccessoryNode()
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
private var selectionNode: GridMessageSelectionNode?
@ -268,7 +267,7 @@ final class GridMessageItemNode: GridItemNode {
badgeContent = .text(inset: 0.0, backgroundColor: mediaBadgeBackgroundColor, foregroundColor: mediaBadgeTextColor, shape: .round, text: NSAttributedString(string: durationString))
}
strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, animated: false)
strongSelf.mediaBadgeNode.update(theme: item.theme, content: badgeContent, mediaDownloadState: mediaDownloadState, alignment: .right, animated: false)
}
}
}))
@ -304,8 +303,7 @@ final class GridMessageItemNode: GridItemNode {
let progressDiameter: CGFloat = 40.0
self.statusNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - progressDiameter) / 2.0), y: floor((imageFrame.size.height - progressDiameter) / 2.0)), size: CGSize(width: progressDiameter, height: progressDiameter))
//self.mediaBadgeNode.frame = CGRect(origin: <#T##CGPoint#>, size: <#T##CGSize#>)
//self.videoAccessoryNode.frame = CGRect(origin: CGPoint(x: imageFrame.maxX - self.videoAccessoryNode.contentSize.width - 5, y: imageFrame.maxY - self.videoAccessoryNode.contentSize.height - 5), size: self.videoAccessoryNode.contentSize)
self.mediaBadgeNode.frame = CGRect(origin: CGPoint(x: imageFrame.width - 3.0, y: imageFrame.height - 18.0 - 3.0), size: CGSize(width: 50.0, height: 50.0))
}
func updateSelectionState(animated: Bool) {

View File

@ -28,7 +28,7 @@ struct InstantPageGalleryEntry: Equatable {
return lhs.index == rhs.index && lhs.pageId == rhs.pageId && lhs.media == rhs.media && lhs.caption == rhs.caption && lhs.credit == rhs.credit && lhs.location == rhs.location
}
func item(context: AccountContext, webPage: TelegramMediaWebpage, presentationData: PresentationData, fromPlayingVideo: Bool, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) -> GalleryItem {
func item(context: AccountContext, webPage: TelegramMediaWebpage, message: Message?, presentationData: PresentationData, fromPlayingVideo: Bool, openUrl: @escaping (InstantPageUrlItem) -> Void, openUrlOptions: @escaping (InstantPageUrlItem) -> Void) -> GalleryItem {
let caption: NSAttributedString
let credit: NSAttributedString
@ -77,7 +77,15 @@ struct InstantPageGalleryEntry: Equatable {
if let location = self.location {
indexData = GalleryItemIndexData(position: location.position, totalCount: location.totalCount)
}
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: .instantPage(self.pageId, file.fileId), fileReference: .webPage(webPage: WebpageReference(webPage), media: file)), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, performAction: { _ in }, openActionOptions: { _ in })
let nativeId: NativeVideoContentId
if let message = message, case let .Loaded(content) = webPage.content, content.file?.fileId == file.fileId {
nativeId = .message(message.id, message.stableId, file.fileId)
} else {
nativeId = .instantPage(self.pageId, file.fileId)
}
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: NativeVideoContent(id: nativeId, fileReference: .webPage(webPage: WebpageReference(webPage), media: file)), originData: nil, indexData: indexData, contentInfo: .webPage(webPage, file), caption: caption, credit: credit, fromPlayingVideo: fromPlayingVideo, performAction: { _ in }, openActionOptions: { _ in })
} else if let embedWebpage = self.media.media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = embedWebpage.content {
if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent) {
return UniversalVideoGalleryItem(context: context, presentationData: presentationData, content: content, originData: nil, indexData: nil, contentInfo: .webPage(webPage, embedWebpage), caption: NSAttributedString(string: ""), fromPlayingVideo: fromPlayingVideo, performAction: { _ in }, openActionOptions: { _ in })
@ -105,6 +113,7 @@ class InstantPageGalleryController: ViewController {
private let context: AccountContext
private let webPage: TelegramMediaWebpage
private let message: Message?
private var presentationData: PresentationData
private let _ready = Promise<Bool>()
@ -137,9 +146,10 @@ class InstantPageGalleryController: ViewController {
private var innerOpenUrl: (InstantPageUrlItem) -> Void
private var openUrlOptions: (InstantPageUrlItem) -> Void
init(context: AccountContext, webPage: TelegramMediaWebpage, entries: [InstantPageGalleryEntry], centralIndex: Int, fromPlayingVideo: Bool = false, replaceRootController: @escaping (ViewController, ValuePromise<Bool>?) -> Void, baseNavigationController: NavigationController?) {
init(context: AccountContext, webPage: TelegramMediaWebpage, message: Message? = nil, entries: [InstantPageGalleryEntry], centralIndex: Int, fromPlayingVideo: Bool = false, replaceRootController: @escaping (ViewController, ValuePromise<Bool>?) -> Void, baseNavigationController: NavigationController?) {
self.context = context
self.webPage = webPage
self.message = message
self.fromPlayingVideo = fromPlayingVideo
self.replaceRootController = replaceRootController
self.baseNavigationController = baseNavigationController
@ -170,7 +180,7 @@ class InstantPageGalleryController: ViewController {
strongSelf.centralEntryIndex = centralIndex
if strongSelf.isViewLoaded {
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
$0.item(context: context, webPage: webPage, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
$0.item(context: context, webPage: webPage, message: message, presentationData: strongSelf.presentationData, fromPlayingVideo: fromPlayingVideo, openUrl: strongSelf.innerOpenUrl, openUrlOptions: strongSelf.openUrlOptions)
}), centralItemIndex: centralIndex, keepFirst: false)
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
@ -309,7 +319,7 @@ class InstantPageGalleryController: ViewController {
}
self.galleryNode.pager.replaceItems(self.entries.map({
$0.item(context: self.context, webPage: self.webPage, presentationData: self.presentationData, fromPlayingVideo: self.fromPlayingVideo, openUrl: self.innerOpenUrl, openUrlOptions: self.openUrlOptions)
$0.item(context: self.context, webPage: self.webPage, message: self.message, presentationData: self.presentationData, fromPlayingVideo: self.fromPlayingVideo, openUrl: self.innerOpenUrl, openUrlOptions: self.openUrlOptions)
}), centralItemIndex: self.centralEntryIndex)
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in

View File

@ -78,7 +78,7 @@ private func chatMessageGalleryControllerData(context: AccountContext, message:
}
}
let gallery = InstantPageGalleryController(context: context, webPage: webPage, entries: instantPageMedia, centralIndex: centralIndex, fromPlayingVideo: fromPlayingVideo, replaceRootController: { [weak navigationController] controller, ready in
let gallery = InstantPageGalleryController(context: context, webPage: webPage, message: message, entries: instantPageMedia, centralIndex: centralIndex, fromPlayingVideo: fromPlayingVideo, replaceRootController: { [weak navigationController] controller, ready in
if let navigationController = navigationController {
navigationController.replaceTopController(controller, animated: false, ready: ready)
}

View File

@ -155,6 +155,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
private var isCentral = false
private var _isVisible = false
private var initiallyActivated = false
private var initiallyAppeared = false
private var validLayout: (ContainerViewLayout, CGFloat)?
private var didPause = false
private var isPaused = true
@ -316,7 +317,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if item.fromPlayingVideo {
videoNode.canAttachContent = false
} else {
//videoNode.canAttachContent = true
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
}
@ -514,6 +514,19 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
private func shouldAutoplayOnCentrality() -> Bool {
if let fetchStatus = self.fetchStatus, let item = self.item, let content = item.content as? NativeVideoContent, let contentInfo = item.contentInfo, case let .message(message) = contentInfo, !self.initiallyActivated {
var isLocal = false
if case .Local = fetchStatus {
isLocal = true
}
if isLocal || isMediaStreamable(message: message, media: content.fileReference.media) {
return true
}
}
return false
}
override func centralityUpdated(isCentral: Bool) {
super.centralityUpdated(isCentral: isCentral)
@ -522,17 +535,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let videoNode = self.videoNode {
if isCentral {
if let fetchStatus = self.fetchStatus, let item = self.item, let content = item.content as? NativeVideoContent, let contentInfo = item.contentInfo, case let .message(message) = contentInfo, !self.initiallyActivated {
if self.shouldAutoplayOnCentrality() {
self.initiallyActivated = true
var isLocal = false
if case .Local = fetchStatus {
isLocal = true
}
if isLocal || isMediaStreamable(message: message, media: content.fileReference.media) {
videoNode.playOnceWithSound(playAndRecord: false, seekToStart: .none, actionAtEnd: .stop)
}
videoNode.playOnceWithSound(playAndRecord: false, seekToStart: .none, actionAtEnd: .stop)
}
//videoNode.canAttachContent = true
} else if videoNode.ownsContentNode {
videoNode.pause()
}
@ -546,7 +552,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if self._isVisible != isVisible {
self._isVisible = isVisible
if let item = self.item, let videoNode = self.videoNode, self.initiallyActivated || !item.fromPlayingVideo {
if let item = self.item, let videoNode = self.videoNode, self.initiallyAppeared || !item.fromPlayingVideo {
videoNode.canAttachContent = isVisible
if isVisible {
videoNode.pause()
@ -555,7 +561,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
videoNode.continuePlayingWithoutSound()
}
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
if self.shouldAutoplayOnCentrality() {
//self.
self.statusButtonNode.isHidden = true
}
}
} else if !isVisible {
self.initiallyAppeared = true
}
}
@ -580,6 +592,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
return
}
self.initiallyAppeared = true
if let node = node.0 as? OverlayMediaItemNode {
var transformedFrame = node.view.convert(node.view.bounds, to: videoNode.view)
let transformedSuperFrame = node.view.convert(node.view.bounds, to: videoNode.view.superview)
@ -649,6 +663,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
Queue.mainQueue().after(0.001) {
videoNode.canAttachContent = true
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
}
if let pictureInPictureNode = self.pictureInPictureNode {