diff --git a/TelegramUI/ChatMessageAttachedContentNode.swift b/TelegramUI/ChatMessageAttachedContentNode.swift index d7b4ceb5df..b46eac957a 100644 --- a/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/TelegramUI/ChatMessageAttachedContentNode.swift @@ -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 diff --git a/TelegramUI/ChatMessageBubbleContentCalclulateImageCorners.swift b/TelegramUI/ChatMessageBubbleContentCalclulateImageCorners.swift index 3f31c822ba..e1fd675071 100644 --- a/TelegramUI/ChatMessageBubbleContentCalclulateImageCorners.swift +++ b/TelegramUI/ChatMessageBubbleContentCalclulateImageCorners.swift @@ -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 { diff --git a/TelegramUI/ChatMessageBubbleContentNode.swift b/TelegramUI/ChatMessageBubbleContentNode.swift index aa8369f834..b502eeaf06 100644 --- a/TelegramUI/ChatMessageBubbleContentNode.swift +++ b/TelegramUI/ChatMessageBubbleContentNode.swift @@ -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 { diff --git a/TelegramUI/ChatMessageBubbleItemNode.swift b/TelegramUI/ChatMessageBubbleItemNode.swift index 09a0ecdb02..4635528375 100644 --- a/TelegramUI/ChatMessageBubbleItemNode.swift +++ b/TelegramUI/ChatMessageBubbleItemNode.swift @@ -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)) diff --git a/TelegramUI/ChatMessageBubbleMosaicLayout.swift b/TelegramUI/ChatMessageBubbleMosaicLayout.swift index 2f00cf8949..fb635000f0 100644 --- a/TelegramUI/ChatMessageBubbleMosaicLayout.swift +++ b/TelegramUI/ChatMessageBubbleMosaicLayout.swift @@ -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 { diff --git a/TelegramUI/ChatMessageInteractiveMediaBadge.swift b/TelegramUI/ChatMessageInteractiveMediaBadge.swift index e63e4acca8..67ce89c91a 100644 --- a/TelegramUI/ChatMessageInteractiveMediaBadge.swift +++ b/TelegramUI/ChatMessageInteractiveMediaBadge.swift @@ -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: {}) + } } } diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index 0f084c056f..c3b26a5984 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -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 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) diff --git a/TelegramUI/ChatMessageMediaBubbleContentNode.swift b/TelegramUI/ChatMessageMediaBubbleContentNode.swift index d1678eafaf..4f55c487af 100644 --- a/TelegramUI/ChatMessageMediaBubbleContentNode.swift +++ b/TelegramUI/ChatMessageMediaBubbleContentNode.swift @@ -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) diff --git a/TelegramUI/ChatMessageWebpageBubbleContentNode.swift b/TelegramUI/ChatMessageWebpageBubbleContentNode.swift index 081bd098bd..72fb2b5ca5 100644 --- a/TelegramUI/ChatMessageWebpageBubbleContentNode.swift +++ b/TelegramUI/ChatMessageWebpageBubbleContentNode.swift @@ -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 } } diff --git a/TelegramUI/FetchCachedRepresentations.swift b/TelegramUI/FetchCachedRepresentations.swift index d171ba564c..3ce268f10b 100644 --- a/TelegramUI/FetchCachedRepresentations.swift +++ b/TelegramUI/FetchCachedRepresentations.swift @@ -8,7 +8,7 @@ import Display import UIKit import AVFoundation -private func resourceData(account: Account, resource: MediaResource, chunkSize: Int) -> Signal { +private func videoFirstFrameData(account: Account, resource: MediaResource, chunkSize: Int) -> Signal { if let size = resource.size { return account.postbox.mediaBox.resourceData(resource, size: size, in: 0 ..< min(size, chunkSize)) |> mapToSignal { _ -> Signal 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() } diff --git a/TelegramUI/GridMessageItem.swift b/TelegramUI/GridMessageItem.swift index 985e0220c3..818fdc9e1d 100644 --- a/TelegramUI/GridMessageItem.swift +++ b/TelegramUI/GridMessageItem.swift @@ -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) { diff --git a/TelegramUI/InstantPageGalleryController.swift b/TelegramUI/InstantPageGalleryController.swift index b248962def..22a9ba3c52 100644 --- a/TelegramUI/InstantPageGalleryController.swift +++ b/TelegramUI/InstantPageGalleryController.swift @@ -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() @@ -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?) -> Void, baseNavigationController: NavigationController?) { + init(context: AccountContext, webPage: TelegramMediaWebpage, message: Message? = nil, entries: [InstantPageGalleryEntry], centralIndex: Int, fromPlayingVideo: Bool = false, replaceRootController: @escaping (ViewController, ValuePromise?) -> 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 diff --git a/TelegramUI/OpenChatMessage.swift b/TelegramUI/OpenChatMessage.swift index 181247ba64..5c23dc82dc 100644 --- a/TelegramUI/OpenChatMessage.swift +++ b/TelegramUI/OpenChatMessage.swift @@ -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) } diff --git a/TelegramUI/UniversalVideoGalleryItem.swift b/TelegramUI/UniversalVideoGalleryItem.swift index 8e97fca3ba..c0f93c3ade 100644 --- a/TelegramUI/UniversalVideoGalleryItem.swift +++ b/TelegramUI/UniversalVideoGalleryItem.swift @@ -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 {