mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-07 13:09:49 +00:00
Inline video playback fixes
This commit is contained in:
parent
a98aa3e57f
commit
1a865367a1
@ -334,7 +334,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
var updateInlineImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
var updateInlineImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
||||||
var textCutout = TextNodeCutout()
|
var textCutout = TextNodeCutout()
|
||||||
var initialWidth: CGFloat = CGFloat.greatestFiniteMagnitude
|
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 refineContentFileLayout: ((CGSize) -> (CGFloat, (CGFloat) -> (CGSize, () -> ChatMessageInteractiveFileNode)))?
|
||||||
|
|
||||||
var contentInstantVideoSizeAndApply: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ContainedViewLayoutTransition) -> ChatMessageInteractiveInstantVideoNode)?
|
var contentInstantVideoSizeAndApply: (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ContainedViewLayoutTransition) -> ChatMessageInteractiveInstantVideoNode)?
|
||||||
@ -377,6 +377,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
textString = string.attributedSubstring(from: NSMakeRange(0, 1000))
|
textString = string.attributedSubstring(from: NSMakeRange(0, 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var automaticPlayback = false
|
||||||
|
|
||||||
if let (media, flags) = mediaAndFlags {
|
if let (media, flags) = mediaAndFlags {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
if file.isInstantVideo {
|
if file.isInstantVideo {
|
||||||
@ -386,7 +388,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
contentInstantVideoSizeAndApply = (videoLayout, apply)
|
contentInstantVideoSizeAndApply = (videoLayout, apply)
|
||||||
} else if file.isVideo {
|
} else if file.isVideo {
|
||||||
var automaticDownload: InteractiveMediaNodeAutodownloadMode = .none
|
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) {
|
if shouldDownloadMediaAutomatically(settings: automaticDownloadSettings, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, authorPeerId: message.author?.id, contactsPeerIds: associatedData.contactsPeerIds, media: file) {
|
||||||
automaticDownload = .full
|
automaticDownload = .full
|
||||||
@ -395,18 +396,25 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
if file.isAnimated {
|
if file.isAnimated {
|
||||||
automaticPlayback = automaticDownloadSettings.autoplayGifs
|
automaticPlayback = automaticDownloadSettings.autoplayGifs
|
||||||
} else {
|
} else if file.isVideo && automaticDownloadSettings.autoplayVideos {
|
||||||
if case .full = automaticDownload, 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
|
automaticPlayback = true
|
||||||
contentMode = .aspectFill
|
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
|
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
|
||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
} else if file.isSticker, let _ = file.dimensions {
|
} 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 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
|
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
|
||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
} else {
|
} else {
|
||||||
@ -431,7 +439,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
} else if let image = media as? TelegramMediaImage {
|
} else if let image = media as? TelegramMediaImage {
|
||||||
if !flags.contains(.preferMediaInline) {
|
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 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
|
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
|
||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
} else if let dimensions = largestImageRepresentation(image.representations)?.dimensions {
|
} else if let dimensions = largestImageRepresentation(image.representations)?.dimensions {
|
||||||
@ -443,11 +451,11 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
} else if let image = media as? TelegramMediaWebFile {
|
} 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 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
|
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
|
||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
} else if let wallpaper = media as? WallpaperPreviewMedia {
|
} 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
|
initialWidth = initialImageWidth + horizontalInsets.left + horizontalInsets.right
|
||||||
refineContentImageLayout = refineLayout
|
refineContentImageLayout = refineLayout
|
||||||
}
|
}
|
||||||
@ -588,7 +596,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
|
|
||||||
var finalizeContentImageLayout: ((CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))?
|
var finalizeContentImageLayout: ((CGFloat) -> (CGSize, (ContainedViewLayoutTransition, Bool) -> ChatMessageInteractiveMediaNode))?
|
||||||
if let refineContentImageLayout = refineContentImageLayout {
|
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
|
finalizeContentImageLayout = finalizeImageLayout
|
||||||
|
|
||||||
boundingSize.width = max(boundingSize.width, refinedWidth)
|
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)
|
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
|
return (adjustedBoundingSize, { [weak self] animation, synchronousLoads in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.context = context
|
strongSelf.context = context
|
||||||
@ -796,13 +806,12 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
strongSelf.additionalImageBadgeNode = updatedAdditionalImageBadge
|
strongSelf.additionalImageBadgeNode = updatedAdditionalImageBadge
|
||||||
contentImageNode.addSubnode(updatedAdditionalImageBadge)
|
contentImageNode.addSubnode(updatedAdditionalImageBadge)
|
||||||
updatedAdditionalImageBadge.update(theme: presentationData.theme.theme, content: additionalImageBadgeContent, mediaDownloadState: nil, animated: false)
|
|
||||||
if mediaBadge != nil {
|
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))
|
updatedAdditionalImageBadge.frame = CGRect(origin: CGPoint(x: 2.0, y: 2.0), size: CGSize(width: 0.0, height: 0.0))
|
||||||
} else {
|
} else {
|
||||||
updatedAdditionalImageBadge.contentMode = .topRight
|
updatedAdditionalImageBadge.update(theme: presentationData.theme.theme, content: additionalImageBadgeContent, mediaDownloadState: nil, alignment: .right, animated: false)
|
||||||
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.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 {
|
} else if let additionalImageBadgeNode = strongSelf.additionalImageBadgeNode {
|
||||||
strongSelf.additionalImageBadgeNode = nil
|
strongSelf.additionalImageBadgeNode = nil
|
||||||
|
@ -23,7 +23,7 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
|
|||||||
topRightCorner = .Corner(mergedRadius)
|
topRightCorner = .Corner(mergedRadius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .mosaic(position):
|
case let .mosaic(position, _):
|
||||||
switch position.topLeft {
|
switch position.topLeft {
|
||||||
case .none:
|
case .none:
|
||||||
topLeftCorner = .Corner(normalRadius)
|
topLeftCorner = .Corner(normalRadius)
|
||||||
@ -69,7 +69,7 @@ func chatMessageBubbleImageContentCorners(relativeContentPosition position: Chat
|
|||||||
bottomRightCorner = .Corner(mergedRadius)
|
bottomRightCorner = .Corner(mergedRadius)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .mosaic(position):
|
case let .mosaic(position, _):
|
||||||
switch position.bottomLeft {
|
switch position.bottomLeft {
|
||||||
case let .none(tail):
|
case let .none(tail):
|
||||||
if tail {
|
if tail {
|
||||||
|
@ -54,7 +54,7 @@ struct ChatMessageBubbleContentMosaicPosition {
|
|||||||
|
|
||||||
enum ChatMessageBubbleContentPosition {
|
enum ChatMessageBubbleContentPosition {
|
||||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||||
case mosaic(position: ChatMessageBubbleContentMosaicPosition)
|
case mosaic(position: ChatMessageBubbleContentMosaicPosition, wide: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ChatMessageBubblePreparePosition {
|
enum ChatMessageBubblePreparePosition {
|
||||||
|
@ -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))
|
contentNodePropertiesAndFinalize.append((contentNodeProperties, contentNodeFinalize))
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@ struct MosaicItemPosition: OptionSet {
|
|||||||
static let right = MosaicItemPosition(rawValue: 8)
|
static let right = MosaicItemPosition(rawValue: 8)
|
||||||
static let inside = MosaicItemPosition(rawValue: 16)
|
static let inside = MosaicItemPosition(rawValue: 16)
|
||||||
static let unknown = MosaicItemPosition(rawValue: 65536)
|
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 {
|
private struct MosaicItemInfo {
|
||||||
|
@ -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
|
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()
|
var contentSize = CGSize()
|
||||||
|
|
||||||
if self.content != content {
|
if self.content != content {
|
||||||
@ -238,7 +192,65 @@ final class ChatMessageInteractiveMediaBadge: ASDisplayNode {
|
|||||||
contentSize = CGSize(width: contentWidth, height: active ? 38.0 : 18.0)
|
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: {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 currentMessage = self.message
|
||||||
let currentMedia = self.media
|
let currentMedia = self.media
|
||||||
let imageLayout = self.imageNode.asyncLayout()
|
let imageLayout = self.imageNode.asyncLayout()
|
||||||
@ -195,7 +195,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
let hasCurrentVideoNode = currentVideoNode != nil
|
let hasCurrentVideoNode = currentVideoNode != nil
|
||||||
let previousAutomaticDownload = self.automaticDownload
|
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
|
var nativeSize: CGSize
|
||||||
|
|
||||||
let isSecretMedia = message.containsSecretMedia
|
let isSecretMedia = message.containsSecretMedia
|
||||||
@ -244,7 +244,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
} else if file.isSticker {
|
} else if file.isSticker {
|
||||||
unboundSize = unboundSize.aspectFilled(CGSize(width: 162.0, height: 162.0))
|
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 {
|
} 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))
|
unboundSize = CGSize(width: floor(dimensions.width * 0.5), height: floor(dimensions.height * 0.5))
|
||||||
} else if let wallpaper = media as? WallpaperPreviewMedia {
|
} else if let wallpaper = media as? WallpaperPreviewMedia {
|
||||||
@ -288,9 +288,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
let _ = PresentationResourcesChat.chatBubbleSecretMediaIcon(theme)
|
let _ = PresentationResourcesChat.chatBubbleSecretMediaIcon(theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (nativeSize, maxWidth, { constrainedSize, corners in
|
return (nativeSize, maxWidth, { constrainedSize, automaticPlayback, corners in
|
||||||
var resultWidth: CGFloat
|
var resultWidth: CGFloat
|
||||||
|
|
||||||
|
isInlinePlayableVideo = isInlinePlayableVideo && automaticPlayback
|
||||||
|
|
||||||
switch sizeCalculation {
|
switch sizeCalculation {
|
||||||
case .constrained:
|
case .constrained:
|
||||||
if isSecretMedia {
|
if isSecretMedia {
|
||||||
@ -585,7 +587,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
updatedPlayerStatusSignal = videoNode.status
|
updatedPlayerStatusSignal = videoNode.status
|
||||||
|> mapToSignal { status -> Signal<MediaPlayerStatus?, NoError> in
|
|> mapToSignal { status -> Signal<MediaPlayerStatus?, NoError> in
|
||||||
if let status = status, case .buffering = status.status {
|
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 {
|
} else {
|
||||||
return .single(status)
|
return .single(status)
|
||||||
}
|
}
|
||||||
@ -906,7 +908,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
|
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
|
||||||
} else {
|
} else {
|
||||||
if automaticPlayback {
|
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)
|
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
|
||||||
} else {
|
} else {
|
||||||
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: sizeString, size: nil, muted: false, active: false)
|
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)
|
badgeContent = .mediaDownload(backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, duration: strings.Conversation_Processing, size: nil, muted: false, active: active)
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
if automaticPlayback && !message.flags.contains(.Unsent), let duration = file.duration {
|
||||||
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
|
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 {
|
} else {
|
||||||
let progressString = String(format: "%d%%", Int(progress * 100.0))
|
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))
|
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) {
|
if !message.flags.contains(.Unsent) {
|
||||||
mediaDownloadState = automaticPlayback ? .none : .compactFetching(progress: progress)
|
state = automaticPlayback ? .none : .play(bubbleTheme.mediaOverlayControlForegroundColor)
|
||||||
state = .none
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let duration = file.duration, !file.isAnimated {
|
if let duration = file.duration, !file.isAnimated {
|
||||||
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
|
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
|
state = automaticPlayback ? .none : state
|
||||||
@ -960,11 +976,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
} else if let file = media as? TelegramMediaFile {
|
} else if let file = media as? TelegramMediaFile {
|
||||||
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && automaticPlayback
|
let isInlinePlayableVideo = file.isVideo && !isSecretMedia && automaticPlayback
|
||||||
if !isInlinePlayableVideo && file.isVideo {
|
if !isInlinePlayableVideo && file.isVideo {
|
||||||
if case .constrained = sizeCalculation {
|
state = .play(bubbleTheme.mediaOverlayControlForegroundColor)
|
||||||
state = .play(bubbleTheme.mediaOverlayControlForegroundColor)
|
|
||||||
} else {
|
|
||||||
state = .none
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
state = .none
|
state = .none
|
||||||
}
|
}
|
||||||
@ -977,11 +989,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
if let file = media as? TelegramMediaFile, let duration = file.duration, !file.isAnimated {
|
if let file = media as? TelegramMediaFile, let duration = file.duration, !file.isAnimated {
|
||||||
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
|
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)
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
case .Remote:
|
case .Remote:
|
||||||
state = .download(bubbleTheme.mediaOverlayControlForegroundColor)
|
state = .download(bubbleTheme.mediaOverlayControlForegroundColor)
|
||||||
@ -998,7 +1006,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if isMediaStreamable(message: message, media: file) {
|
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))
|
badgeContent = .text(inset: 12.0, backgroundColor: bubbleTheme.mediaDateAndStatusFillColor, foregroundColor: bubbleTheme.mediaDateAndStatusTextColor, shape: .round, text: NSAttributedString(string: durationString))
|
||||||
mediaDownloadState = .compactRemote
|
mediaDownloadState = .compactRemote
|
||||||
} else {
|
} 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()
|
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 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 {
|
if let node = node, let currentAsyncLayout = currentAsyncLayout {
|
||||||
imageNode = node
|
imageNode = node
|
||||||
@ -1090,10 +1098,10 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
imageLayout = imageNode.asyncLayout()
|
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
|
return (unboundSize, initialWidth, { constrainedSize, automaticPlayback, corners in
|
||||||
let (finalWidth, finalLayout) = continueLayout(constrainedSize, corners)
|
let (finalWidth, finalLayout) = continueLayout(constrainedSize, automaticPlayback, corners)
|
||||||
|
|
||||||
return (finalWidth, { boundingWidth in
|
return (finalWidth, { boundingWidth in
|
||||||
let (finalSize, apply) = finalLayout(boundingWidth)
|
let (finalSize, apply) = finalLayout(boundingWidth)
|
||||||
|
@ -81,7 +81,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if telegramFile.isAnimated {
|
if telegramFile.isAnimated {
|
||||||
automaticPlayback = item.controllerInteraction.automaticMediaDownloadSettings.autoplayGifs
|
automaticPlayback = item.controllerInteraction.automaticMediaDownloadSettings.autoplayGifs
|
||||||
contentMode = .aspectFill
|
contentMode = .aspectFill
|
||||||
} else if telegramFile.isVideo && item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos, case .linear = preparePosition {
|
} else if telegramFile.isVideo && item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos {
|
||||||
var willDownloadOrLocal = false
|
var willDownloadOrLocal = false
|
||||||
if case .full = automaticDownload {
|
if case .full = automaticDownload {
|
||||||
willDownloadOrLocal = true
|
willDownloadOrLocal = true
|
||||||
@ -121,12 +121,16 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
sizeCalculation = .unconstrained
|
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 forceFullCorners = false
|
||||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 7.0, hidesBackground: .emptyWallpaper, forceFullCorners: forceFullCorners, forceAlignment: .none)
|
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
|
return (contentProperties, unboundSize, initialWidth + bubbleInsets.left + bubbleInsets.right, { constrainedSize, position in
|
||||||
|
if case let .mosaic(_, wide) = position {
|
||||||
|
automaticPlayback = automaticPlayback && wide
|
||||||
|
}
|
||||||
|
|
||||||
var updatedPosition: ChatMessageBubbleContentPosition = position
|
var updatedPosition: ChatMessageBubbleContentPosition = position
|
||||||
if forceFullCorners, case .linear = updatedPosition {
|
if forceFullCorners, case .linear = updatedPosition {
|
||||||
updatedPosition = .linear(top: .None(.None(.None)), bottom: .None(.None(.None)))
|
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 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
|
return (refinedWidth + bubbleInsets.left + bubbleInsets.right, { boundingWidth in
|
||||||
let (imageSize, imageApply) = finishLayout(boundingWidth - bubbleInsets.left - bubbleInsets.right)
|
let (imageSize, imageApply) = finishLayout(boundingWidth - bubbleInsets.left - bubbleInsets.right)
|
||||||
|
@ -229,9 +229,16 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
var mainMedia: Media?
|
var mainMedia: Media?
|
||||||
|
|
||||||
var automaticPlayback = false
|
var automaticPlayback = false
|
||||||
|
|
||||||
if let file = webpage.file, !file.isAnimated, item.controllerInteraction.automaticMediaDownloadSettings.autoplayVideos {
|
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) {
|
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
|
automaticPlayback = true
|
||||||
|
} else {
|
||||||
|
automaticPlayback = item.context.account.postbox.mediaBox.completedResourcePath(file.resource) != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import Display
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AVFoundation
|
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 {
|
if let size = resource.size {
|
||||||
return account.postbox.mediaBox.resourceData(resource, size: size, in: 0 ..< min(size, chunkSize))
|
return account.postbox.mediaBox.resourceData(resource, size: size, in: 0 ..< min(size, chunkSize))
|
||||||
|> mapToSignal { _ -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
|> mapToSignal { _ -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||||
@ -19,7 +19,7 @@ private func resourceData(account: Account, resource: MediaResource, chunkSize:
|
|||||||
if chunkSize > size {
|
if chunkSize > size {
|
||||||
return .complete()
|
return .complete()
|
||||||
} else {
|
} 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()
|
return .complete()
|
||||||
}
|
}
|
||||||
} else if let size = resource.size {
|
} 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 {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,6 @@ final class GridMessageItemNode: GridItemNode {
|
|||||||
private var item: GridMessageItem?
|
private var item: GridMessageItem?
|
||||||
private var controllerInteraction: ChatControllerInteraction?
|
private var controllerInteraction: ChatControllerInteraction?
|
||||||
private var statusNode: RadialStatusNode
|
private var statusNode: RadialStatusNode
|
||||||
//private let videoAccessoryNode = GridMessageVideoAccessoryNode()
|
|
||||||
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
|
private let mediaBadgeNode: ChatMessageInteractiveMediaBadge
|
||||||
|
|
||||||
private var selectionNode: GridMessageSelectionNode?
|
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))
|
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
|
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.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.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))
|
||||||
//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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSelectionState(animated: Bool) {
|
func updateSelectionState(animated: Bool) {
|
||||||
|
@ -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
|
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 caption: NSAttributedString
|
||||||
let credit: NSAttributedString
|
let credit: NSAttributedString
|
||||||
|
|
||||||
@ -77,7 +77,15 @@ struct InstantPageGalleryEntry: Equatable {
|
|||||||
if let location = self.location {
|
if let location = self.location {
|
||||||
indexData = GalleryItemIndexData(position: location.position, totalCount: location.totalCount)
|
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 {
|
} else if let embedWebpage = self.media.media as? TelegramMediaWebpage, case let .Loaded(webpageContent) = embedWebpage.content {
|
||||||
if let content = WebEmbedVideoContent(webPage: embedWebpage, webpageContent: webpageContent) {
|
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 })
|
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 context: AccountContext
|
||||||
private let webPage: TelegramMediaWebpage
|
private let webPage: TelegramMediaWebpage
|
||||||
|
private let message: Message?
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
@ -137,9 +146,10 @@ class InstantPageGalleryController: ViewController {
|
|||||||
private var innerOpenUrl: (InstantPageUrlItem) -> Void
|
private var innerOpenUrl: (InstantPageUrlItem) -> Void
|
||||||
private var openUrlOptions: (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.context = context
|
||||||
self.webPage = webPage
|
self.webPage = webPage
|
||||||
|
self.message = message
|
||||||
self.fromPlayingVideo = fromPlayingVideo
|
self.fromPlayingVideo = fromPlayingVideo
|
||||||
self.replaceRootController = replaceRootController
|
self.replaceRootController = replaceRootController
|
||||||
self.baseNavigationController = baseNavigationController
|
self.baseNavigationController = baseNavigationController
|
||||||
@ -170,7 +180,7 @@ class InstantPageGalleryController: ViewController {
|
|||||||
strongSelf.centralEntryIndex = centralIndex
|
strongSelf.centralEntryIndex = centralIndex
|
||||||
if strongSelf.isViewLoaded {
|
if strongSelf.isViewLoaded {
|
||||||
strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({
|
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)
|
}), centralItemIndex: centralIndex, keepFirst: false)
|
||||||
|
|
||||||
let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
|
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({
|
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)
|
}), centralItemIndex: self.centralEntryIndex)
|
||||||
|
|
||||||
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in
|
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in
|
||||||
|
@ -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 {
|
if let navigationController = navigationController {
|
||||||
navigationController.replaceTopController(controller, animated: false, ready: ready)
|
navigationController.replaceTopController(controller, animated: false, ready: ready)
|
||||||
}
|
}
|
||||||
|
@ -155,6 +155,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
private var isCentral = false
|
private var isCentral = false
|
||||||
private var _isVisible = false
|
private var _isVisible = false
|
||||||
private var initiallyActivated = false
|
private var initiallyActivated = false
|
||||||
|
private var initiallyAppeared = false
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
private var didPause = false
|
private var didPause = false
|
||||||
private var isPaused = true
|
private var isPaused = true
|
||||||
@ -316,7 +317,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
if item.fromPlayingVideo {
|
if item.fromPlayingVideo {
|
||||||
videoNode.canAttachContent = false
|
videoNode.canAttachContent = false
|
||||||
} else {
|
} else {
|
||||||
//videoNode.canAttachContent = true
|
|
||||||
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
|
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) {
|
override func centralityUpdated(isCentral: Bool) {
|
||||||
super.centralityUpdated(isCentral: isCentral)
|
super.centralityUpdated(isCentral: isCentral)
|
||||||
|
|
||||||
@ -522,17 +535,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
|
|
||||||
if let videoNode = self.videoNode {
|
if let videoNode = self.videoNode {
|
||||||
if isCentral {
|
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
|
self.initiallyActivated = true
|
||||||
var isLocal = false
|
videoNode.playOnceWithSound(playAndRecord: false, seekToStart: .none, actionAtEnd: .stop)
|
||||||
if case .Local = fetchStatus {
|
|
||||||
isLocal = true
|
|
||||||
}
|
|
||||||
if isLocal || isMediaStreamable(message: message, media: content.fileReference.media) {
|
|
||||||
videoNode.playOnceWithSound(playAndRecord: false, seekToStart: .none, actionAtEnd: .stop)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//videoNode.canAttachContent = true
|
|
||||||
} else if videoNode.ownsContentNode {
|
} else if videoNode.ownsContentNode {
|
||||||
videoNode.pause()
|
videoNode.pause()
|
||||||
}
|
}
|
||||||
@ -546,7 +552,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
if self._isVisible != isVisible {
|
if self._isVisible != isVisible {
|
||||||
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
|
videoNode.canAttachContent = isVisible
|
||||||
if isVisible {
|
if isVisible {
|
||||||
videoNode.pause()
|
videoNode.pause()
|
||||||
@ -555,7 +561,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||||||
videoNode.continuePlayingWithoutSound()
|
videoNode.continuePlayingWithoutSound()
|
||||||
}
|
}
|
||||||
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.initiallyAppeared = true
|
||||||
|
|
||||||
if let node = node.0 as? OverlayMediaItemNode {
|
if let node = node.0 as? OverlayMediaItemNode {
|
||||||
var transformedFrame = node.view.convert(node.view.bounds, to: videoNode.view)
|
var transformedFrame = node.view.convert(node.view.bounds, to: videoNode.view)
|
||||||
let transformedSuperFrame = node.view.convert(node.view.bounds, to: videoNode.view.superview)
|
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) {
|
Queue.mainQueue().after(0.001) {
|
||||||
videoNode.canAttachContent = true
|
videoNode.canAttachContent = true
|
||||||
|
self.updateDisplayPlaceholder(!videoNode.ownsContentNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let pictureInPictureNode = self.pictureInPictureNode {
|
if let pictureInPictureNode = self.pictureInPictureNode {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user