mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-06 20:54:04 +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 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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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: {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user